mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:46 +01:00
feat(mihomo): answer AAAA and keep the tailnet off the TUN
fake-ip needs one pool per family, and the family a client picks does not pick the egress family. Exclude the cluster ULA and the Tailscale ranges from the TUN; the ssh pin and the WA-028 record cover the fake-AAAA stall.
This commit is contained in:
1 parent
9cf0a92a30
commit
1e6702db2c
7 files changed
+48
-26
No files matched your search
+3
-1
@@ -34,7 +34,7 @@ A version or revision pinned for a reason that can go away.
|
||||
A setting that works around a bug or a hardware quirk.
|
||||
|
||||
| ID | What & where | Why | Removal condition | Added | Revisit | Status |
|
||||
| ------ | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------ | ------ |
|
||||
| ------ | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------ | ------ |
|
||||
| WA-008 | Relaxed NVMe APST (`nvme_core.default_ps_max_latency_us=100000`) — `hosts/idols-ai/hardware-configuration.nix` | the KINGBANK KP260 (DRAM-less QLC) froze on slow APST wake-ups | Drop the override once kernel/firmware fixes or replacement hardware make default APST reliable | 2026-10-03 | watch NVMe timeout/reset/AER in the journal | active |
|
||||
| WA-009 | USB-SATA bridge mitigations (`usbcore.autosuspend=-1`, `usb-storage.delay_use=10`) — `hosts/12kingdoms-youko/default.nix` | flaky JMicron JMS567 resets with UDMA-CRC and I/O errors | Drop once the bridge/controller is replaced; the signal is smartctl CRC/media errors | 2026-09-21 | on hardware change or CRC errors | active |
|
||||
| WA-010 | Insta360 Link USB reset on S3 resume — `hosts/idols-ai/default.nix` | the camera stays enumerated with a stalled UVC endpoint after resume | Drop after the Insta360 firmware or the kernel `uvcvideo` fixes it | 2026-08-01 | on kernel or firmware change | active |
|
||||
@@ -43,6 +43,8 @@ A setting that works around a bug or a hardware quirk.
|
||||
| WA-018 | user-owned `~/.ssh/config` + disabled systemd ssh-proxy include — `home/base/tui/ssh.nix`, `modules/nixos/base/ssh.nix` | bwrap exposes root-owned store files as `nobody` | Drop once sandboxes preserve store ownership | 2026-10-06 | when sandbox layout changes | active |
|
||||
| WA-019 | programs.steam.extraCompatPackages = [ pkgs.dwproton-bin pkgs.proton-ge-bin ] — modules/nixos/desktop/gaming.nix | ACE games fail on GE/mainline Proton, work with DW-Proton | Drop once mainline or GE-Proton runs these games (GE-Proton#433) | 2026-10-07 | on Proton/GE bump | active |
|
||||
| WA-024 | Wi-Fi power saving disabled (`networking.networkmanager.wifi.powersave = false`) — `hosts/12kingdoms-shoukei/apple-silicon.nix` | On this BCM4378/brcmfmac laptop, powersave is a common source of intermittent ASSOC-REJECT / authentication-timeout failures; NetworkManager then mistakes the failure for a bad key, re-prompts, and the client (Noctalia, nmtui, nmcli) saves the answer as a duplicate `<SSID> 1` profile | Drop once the kernel carries the brcmfmac `port_authorized` fix (WA-025) and no association failures remain | 2026-10-07 | watch `journalctl -u wpa_supplicant` for ASSOC-REJECT / authentication timeout | active |
|
||||
| WA-026 | guest deploys run `installOnHost` then `systemctl restart microvm@<guest>`, not `just microvm-deploy` — `lib/genMicrovmGuestModule.nix` | the sshSwitch step runs `nix-store --load-db` against the guest's read-only virtiofs `/nix/store` and dies on `cannot remount "/nix/store" writable` (nix 2.35) | Drop the manual path once microvm.nix or nix handles a read-only store switch | 2026-10-09 | on microvm.nix or nix bump | active |
|
||||
| WA-028 | `github.com` keeps `AddressFamily = "inet"` — `home/base/tui/ssh.nix` | measured on 1.19.31 + `tun.stack: gvisor`: TCP to a fake IPv6 is proxied and SSH even authenticates (`[fdfe:dcba:9876::18]:443`), but the session then never closes, while the same run over the fake IPv4 ends cleanly. HTTPS over a fake IPv6 is fine, so only ssh needs the pin | Drop the line once `git ls-remote` with `AddressFamily=any` returns a sha instead of hanging | 2026-10-09 | on a mihomo bump, or if `tun.stack` changes | active |
|
||||
|
||||
If WA-008 freezes recur, the fallback is to restore
|
||||
`nvme_core.default_ps_max_latency_us=0 nvme_core.io_timeout=4294967295 pcie_aspm=off`; this is a
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
settings = {
|
||||
"github.com" = {
|
||||
# avoid mihomo fake-IP6 hang, see modules/nixos/desktop/networking/mihomo/
|
||||
# WA-028: pinned to IPv4 until the mihomo v6 fake-ip pool is proven here
|
||||
AddressFamily = "inet";
|
||||
HostName = "ssh.github.com";
|
||||
Port = 443;
|
||||
|
||||
@@ -43,17 +43,26 @@ targets instead of writing a config the core rejects.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `ipv6: false`: nodes without IPv6 egress + AAAA = routing black hole (WeChat/JD/Taobao images);
|
||||
mihomo's IPv6 fake-ip also hung ssh/git locally for ~2 minutes, so it stays off.
|
||||
- `ipv6`, `dns.ipv6`, `fake-ip-range6`: the fake v6 pool is a lookup key, so the family the client
|
||||
picks never picks the egress family -- a fake-IPv6 client dials an IPv4 proxy target, and CN
|
||||
services answer identically over `-6` and `-4`. What does break is a fake v6 pool on a line whose
|
||||
IPv6 is dead: apps that resolve for themselves (WeChat) dial a real AAAA, stall, and do not fall
|
||||
back. mihomo has no IPv6 reachability probe (mihomo#2233), so the config has to match the line.
|
||||
SSH over a fake AAAA is the local exception: it connects, authenticates, then never closes --
|
||||
WA-028's IPv4 pin covers it.
|
||||
- `private_domains`: each entry becomes a DIRECT rule + a `fake-ip-filter` entry.
|
||||
- WeChat/QQ media go over bare CDN IPs, hence `multimedia.nt.qq.com.cn` in `fake-ip-filter`. If
|
||||
media still stalls: `tun_exclude_process: [wechat, WeChatAppEx, qq]` (Linux names; the fix that
|
||||
won clash-verge-rev#1762).
|
||||
- WeChat resolves for itself, but its queries still cross the TUN, so `dns-hijack: any:53` catches
|
||||
them and the fake-ip table hands the name back to the rules: `mmbiz.qpic.cn` measured DIRECT.
|
||||
`multimedia.nt.qq.com.cn` stays in `fake-ip-filter` for the same reason. The exclude-process fix
|
||||
that won clash-verge-rev#1762 is not available here: `hardening/bwraps/wechat.nix` sets
|
||||
`unsharePid = true` and the sandbox reports uid 0, so no process name resolves.
|
||||
- `find-process-mode: off` unless `PROCESS-*` rules or `tun_exclude_process` need it.
|
||||
- `tun_exclude_address`: a destination that can never be a proxy target should not pay a fake-ip
|
||||
round trip -- RFC1918, RFC 6598's `100.64.0.0/10` (where Tailscale addresses come from),
|
||||
link-local, multicast, reserved and documentation prefixes, `fc00::/7`, `fe80::/10`. Never exclude
|
||||
`198.18.0.0/15`, the fake-ip range itself; `tun_exclude_address: []` puts everything back in TUN.
|
||||
link-local, multicast, reserved and documentation prefixes, the cluster ULA `fd05:5::/64` and
|
||||
Tailscale's `fd7a:115c:a1e0::/48`. Never exclude a range that holds a fake-ip pool: that is
|
||||
`198.18.0.0/16` and `fdfe:dcba:9876::/64`, which is why the list spells the two ULAs out instead
|
||||
of taking `fc00::/7`; `tun_exclude_address: []` puts everything back in TUN.
|
||||
- Steam's download caches follow the public IP Steam sees on the login (CM) connection, so a proxied
|
||||
Steam downloads from Tokyo/Singapore/HK/Los Angeles. `policy.yaml` pins the CM hosts,
|
||||
`steamcontent.com` and `IP-ASN,32590` DIRECT and keeps `steamcommunity.com` on the proxy -- Steam
|
||||
@@ -106,9 +115,12 @@ grep -oE 'cache[0-9]+-[a-z]{3}[0-9]+' ~/.local/share/Steam/logs/content_log.txt
|
||||
## References
|
||||
|
||||
- [clash-verge-rev#1762](https://github.com/clash-verge-rev/clash-verge-rev/issues/1762) — WeChat
|
||||
media under TUN: fake-ip-filter, qlogo/qpic, the exclude-process fix.
|
||||
- [WeChat-under-TUN retrospective](https://x.com/realchendahuang/status/2104381806862795161) — the
|
||||
IPv6 black hole logic; JD and Taobao break the same way.
|
||||
media under TUN: fake-ip-filter, qlogo/qpic, the exclude-process fix. Its closing comment is the
|
||||
one that matters: a fake v6 pool works on a line with working IPv6 and hangs on a line without.
|
||||
- [mihomo#2233](https://github.com/MetaCubeX/mihomo/issues/2233) — open: the core has no IPv6
|
||||
reachability probe, so `ipv6` cannot stay on for a line that lost IPv6.
|
||||
- [WeChat-under-TUN retrospective](https://x.com/realchendahuang/status/2104381806862795161) — five
|
||||
community fixes; "turn IPv6 off" only ever worked where the line's IPv6 was already broken.
|
||||
- [mihomo wiki](https://wiki.metacubex.one/),
|
||||
[proxy providers](https://wiki.metacubex.one/config/proxy-providers/) — why subscription rules are
|
||||
dropped.
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
# The config stays OUT of the Nix store (it holds subscription URLs and the
|
||||
# controller secret) and reaches the service through systemd's LoadCredential.
|
||||
# This module only wires up the service; generate the file with ./generate.nu.
|
||||
# See README.md for usage and the routing notes, in particular why the config
|
||||
# must keep `ipv6: false`: mihomo does not proxy TCP to an IPv6 fake-IP
|
||||
# (fdfe:dcba:9876::/64), so ssh/git connections hang until they time out
|
||||
# (home/base/tui/ssh.nix keeps `AddressFamily inet` as a per-client fallback).
|
||||
# See README.md for usage and the routing notes, in particular the IPv6
|
||||
# condition: the fake-ip v6 pool needs a line whose IPv6 actually works, and
|
||||
# mihomo has no reachability probe to notice when the line loses it.
|
||||
let
|
||||
cfg = config.modules.networking.mihomo;
|
||||
configFile = "${config.users.users.${myvars.username}.home}/.config/mihomo/config.yaml";
|
||||
|
||||
@@ -31,7 +31,6 @@ def main [
|
||||
|
||||
let gw = (open --raw $tmp
|
||||
| from yaml
|
||||
| update ipv6 true
|
||||
| update allow-lan true
|
||||
| update external-controller $"($address):9090"
|
||||
| insert tproxy-port 7893
|
||||
@@ -40,9 +39,8 @@ def main [
|
||||
| update secret "GATEWAY-SECRET-PLACEHOLDER"
|
||||
| update tun.stack "mixed"
|
||||
| update tun.strict-route false
|
||||
| insert tun.route-address ["0.0.0.0/1", "128.0.0.0/1", "::/1", "8000::/1"]
|
||||
| update dns.listen ":1053"
|
||||
| update dns.ipv6 true)
|
||||
# the desktop's resolver is loopback; a gateway serves the LAN instead
|
||||
| update dns.listen ":1053")
|
||||
|
||||
let gw = (if $redact {
|
||||
# a file-backed provider (localyaml) has no url to hide
|
||||
|
||||
@@ -496,10 +496,10 @@ def main [
|
||||
let fpm = (process_mode $all_rules $excluded)
|
||||
|
||||
let config = {
|
||||
# IPv6 stays off on purpose: most proxy nodes have no IPv6 egress, so an
|
||||
# AAAA record becomes a routing black hole that apps such as WeChat, JD,
|
||||
# Taobao and Feishu sit on until they fall back to IPv4.
|
||||
ipv6: false
|
||||
# IPv6 on. fake-ip answers AAAA from a v6 pool, so the family the client
|
||||
# picks never decides the egress family: mihomo dials the proxy, the proxy
|
||||
# dials IPv4. Taobao, JD, WeChat and Bilibili answer identically over -6 and -4.
|
||||
ipv6: true
|
||||
mode: "rule"
|
||||
"mixed-port": 7897
|
||||
"allow-lan": false
|
||||
@@ -533,9 +533,12 @@ def main [
|
||||
# answers over loopback (systemd-resolved) need their resolver taken over
|
||||
# while mihomo runs, or fake-ip is bypassed entirely.
|
||||
listen: "127.0.0.1:1053"
|
||||
ipv6: false
|
||||
ipv6: true
|
||||
"enhanced-mode": "fake-ip"
|
||||
"fake-ip-range": "198.18.0.1/16"
|
||||
# AAAA needs a pool of its own (fake-ip-range6, mihomo >= 1.19.16); one
|
||||
# prefix per family, no comma list. Keep it out of route-exclude-address.
|
||||
"fake-ip-range6": "fdfe:dcba:9876::1/64"
|
||||
"fake-ip-filter-mode": "blacklist"
|
||||
"prefer-h3": false
|
||||
"respect-rules": false
|
||||
|
||||
@@ -63,7 +63,8 @@ tun_exclude_address:
|
||||
- 203.0.113.0/24
|
||||
- 224.0.0.0/4 # multicast: mDNS, SSDP
|
||||
- 240.0.0.0/4 # reserved, includes limited broadcast
|
||||
- fc00::/7 # ULA: home network and Tailscale IPv6
|
||||
- fd05:5::/64 # clusterULA6: the k3s node plane, on-link on the LAN
|
||||
- fd7a:115c:a1e0::/48 # Tailscale IPv6 CGNAT: stays on tailscale0
|
||||
- fe80::/10
|
||||
- 2001:db8::/32 # IPv6 documentation
|
||||
- 2002::/16 # deprecated 6to4
|
||||
@@ -126,6 +127,9 @@ rules:
|
||||
|
||||
# local ranges, by address as well as by name
|
||||
- DOMAIN-SUFFIX,lan,DIRECT
|
||||
# MagicDNS names are dialed by name, so the tailnet CIDR rules below cannot see
|
||||
# them; a proxied tailnet peer is unreachable either way.
|
||||
- DOMAIN-SUFFIX,ts.net,DIRECT
|
||||
- IP-CIDR,0.0.0.0/8,DIRECT,no-resolve
|
||||
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
|
||||
- IP-CIDR,100.64.0.0/10,DIRECT,no-resolve
|
||||
@@ -134,6 +138,10 @@ rules:
|
||||
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
|
||||
- IP-CIDR,224.0.0.0/4,DIRECT,no-resolve
|
||||
- IP-CIDR6,fe80::/10,DIRECT,no-resolve
|
||||
# IPv6 counterparts of the LAN and tailnet CIDR rules above; a belt for the
|
||||
# route-exclude-address entries, which keep these off the TUN already.
|
||||
- IP-CIDR6,fd05:5::/64,DIRECT,no-resolve
|
||||
- IP-CIDR6,fd7a:115c:a1e0::/48,DIRECT,no-resolve
|
||||
|
||||
# everything else that is CN by geolocation, then the catch-all
|
||||
- GEOSITE,cn,DIRECT
|
||||
|
||||
Reference in new issue
Block a user