mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:46 +01:00
fix(desktop): tie ai's link DNS takeover to mihomo's lifecycle (#380)
* fix(desktop): tie ai's link DNS takeover to mihomo's lifecycle sing-tun normally points systemd-resolved at the TUN DNS by running resolvectl (dns/domain/default-route). Under nixpkgs' hardened DynamicUser mihomo unit that hand-off fails silently: the unit's RestrictAddressFamilies blocks resolvectl's D-Bus socket and resolve1 requires privileged authorization, so resolved keeps querying the physical-link DNS, fake-ip is bypassed, and domain rules degrade to MATCH. Do the hand-off as '+' ExecStartPost/ExecStopPost hooks instead: '+' commands run outside the sandbox (systemd.exec: address-family restrictions do not apply to them) and ExecStopPost reverts even on crashes, so a dead mihomo leaves DNS usable. Signed-off-by: Ryan Yin <xiaoyin_c@qq.com> * docs(mihomo): record sing-tun's resolvectl hand-off as the leak cause Signed-off-by: Ryan Yin <xiaoyin_c@qq.com> * refactor(desktop): keep mihomo only on ai and shoukei ruby/kana never ran the core (service inactive live), and their resolved + TUN combo would reintroduce the resolver leak once enabled. Drop the enable and the explicit module import from computer-use; the eval test now pins mihomo=false for both guests. --------- Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>
This commit is contained in:
1 parent
bbd230e6fd
commit
8f0961d9c2
7 files changed
+42
-22
No files matched your search
@@ -24,17 +24,18 @@ bump, and the commands that destroy rollback points are in the `nix-config-updat
|
||||
|
||||
## 1. Localize by layer
|
||||
|
||||
| Layer | Symptom | Look with |
|
||||
| ------------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| eval | `just test` prints `false`, an eval error | `just eval-host <host>` (already passes `--show-trace`) |
|
||||
| build | build error, hash mismatch, "marked as broken" | `just build-host <host>`, then `nix log <drv>` |
|
||||
| activation | the deploy fails after building | the deploy output; `journalctl -u home-manager-$USER -b` for Home Manager |
|
||||
| runtime | a unit is failed or restarting | `just list-failed`, `systemctl status <unit>`, `journalctl -u <unit> -b` |
|
||||
| boot | errors at boot, wrong kernel | `journalctl -b -p err`; `just history` for what is booted |
|
||||
| session | desktop or app misbehaves | `journalctl --user -b -p err`; the `nix-config-desktop` skill |
|
||||
| remote host | anything on a Colmena host | `ssh root@<host> journalctl -b -p err`, same commands over SSH |
|
||||
| MicroVM guest | guest down or unreachable | on the VM host: `systemctl status microvm@<guest>` and `microvm-tap-interfaces@<guest>`; then `br0` |
|
||||
| secrets | missing or unreadable `/etc/agenix/*` | the `nix-config-secrets` skill |
|
||||
| Layer | Symptom | Look with |
|
||||
| ------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| eval | `just test` prints `false`, an eval error | `just eval-host <host>` (already passes `--show-trace`) |
|
||||
| build | build error, hash mismatch, "marked as broken" | `just build-host <host>`, then `nix log <drv>` |
|
||||
| activation | the deploy fails after building | the deploy output; `journalctl -u home-manager-$USER -b` for Home Manager |
|
||||
| runtime | a unit is failed or restarting | `just list-failed`, `systemctl status <unit>`, `journalctl -u <unit> -b` |
|
||||
| proxy/DNS | proxied sites time out, node and rules look ok | `dig +short <site>` must return a fake-ip (`198.18.x.x`); a real IP means the system resolver bypasses `dns-hijack` — mihomo README Gotchas |
|
||||
| boot | errors at boot, wrong kernel | `journalctl -b -p err`; `just history` for what is booted |
|
||||
| session | desktop or app misbehaves | `journalctl --user -b -p err`; the `nix-config-desktop` skill |
|
||||
| remote host | anything on a Colmena host | `ssh root@<host> journalctl -b -p err`, same commands over SSH |
|
||||
| MicroVM guest | guest down or unreachable | on the VM host: `systemctl status microvm@<guest>` and `microvm-tap-interfaces@<guest>`; then `br0` |
|
||||
| secrets | missing or unreadable `/etc/agenix/*` | the `nix-config-secrets` skill |
|
||||
|
||||
## 2. Read the evaluated value
|
||||
|
||||
|
||||
@@ -59,7 +59,10 @@ assume the physical-host deployment is done through Colmena.
|
||||
unused `args`: haumea passes them lazily and they are still required.
|
||||
5. `vars/networking.nix` - `hostsAddr.<name> = { iface; ipv4; }` for a LAN host. That entry drives
|
||||
the static address, the SSH `Host` alias used for remote builds, and `known_hosts`, so a wrong
|
||||
`iface` takes the host offline at activation. Skip it for a DHCP or mobile host.
|
||||
`iface` takes the host offline at activation. Skip it for a DHCP or mobile host. If the host
|
||||
enables `modules.networking.mihomo` and runs systemd-resolved, it needs a DNS takeover tied to
|
||||
mihomo's lifecycle (`resolvectl dns`/`revert` in `ExecStartPost`/`ExecStopPost`, see
|
||||
`hosts/idols-ai/default.nix`); a static link DNS would kill DNS when mihomo dies.
|
||||
6. `hosts/README.md` - add the host to the inventory.
|
||||
|
||||
Pin service user and group ids (`service-user-ids.nix`, as on `shoryu`) before the host has state on
|
||||
|
||||
@@ -136,6 +136,20 @@ in
|
||||
linkConfig.RequiredForOnline = "routable";
|
||||
};
|
||||
|
||||
# Dynamic DNS takeover: sing-tun normally asks resolved to use the TUN DNS
|
||||
# address through resolvectl. That built-in call is not usable from nixpkgs'
|
||||
# DynamicUser+hardened unit: the D-Bus socket is blocked, and resolve1's
|
||||
# SetLinkDNS/SetLinkDomains methods require privileged authorization. Without
|
||||
# it, resolved's upstream queries bypass dns-hijack and leave via the NIC.
|
||||
# Run the takeover as a privileged lifecycle hook instead. ExecStopPost also
|
||||
# runs on crashes, so a dead mihomo leaves the network usable.
|
||||
# The '+' prefix escapes the unit's sandbox; without it, resolvectl's D-Bus
|
||||
# connect fails and a failed ExecStartPost kills the otherwise healthy service.
|
||||
systemd.services.mihomo.serviceConfig = {
|
||||
ExecStartPost = lib.mkDefault "+${pkgs.systemd}/bin/resolvectl dns ${iface} 127.0.0.1:1053";
|
||||
ExecStopPost = lib.mkDefault "+${pkgs.systemd}/bin/resolvectl revert ${iface}";
|
||||
};
|
||||
|
||||
# This value determines the NixOS release from which the default
|
||||
# settings for stateful data, like file locations and database versions
|
||||
# on your system were taken. It‘s perfectly fine and recommended to leave
|
||||
|
||||
@@ -14,8 +14,6 @@ let
|
||||
timeZone = if cfg.proxyRegion == "jp" then "Asia/Tokyo" else "America/Los_Angeles";
|
||||
in
|
||||
{
|
||||
imports = [ ./networking/mihomo ]; # also pulled in by the desktop scanPaths; explicit for clarity
|
||||
|
||||
options.modules.desktop.computerUse = {
|
||||
enable = lib.mkEnableOption "headless computer-use environment (X11 + desktop automation)";
|
||||
proxyRegion = lib.mkOption {
|
||||
@@ -46,10 +44,5 @@ in
|
||||
|
||||
# Browsers keep their profile/preferences in dconf.
|
||||
programs.dconf.enable = true;
|
||||
|
||||
# Native mihomo runs the proxy as a system service (TUN), so the headless
|
||||
# session does not depend on a GUI starting the core. Its config lives at
|
||||
# ~/.config/mihomo/config.yaml (out of the Nix store).
|
||||
modules.networking.mihomo.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Mihomo
|
||||
|
||||
Native mihomo core + metacubexd dashboard, replacing the Clash Verge GUI. Enable per host with
|
||||
`modules.networking.mihomo.enable = true` (`ai`, `shoukei`, `ruby`, `kana`).
|
||||
`modules.networking.mihomo.enable = true` (`ai`, `shoukei`).
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -46,6 +46,13 @@ targets instead of writing a config the core rejects.
|
||||
won clash-verge-rev#1762).
|
||||
- `find-process-mode: off` unless `PROCESS-*` rules or `tun_exclude_process` need it.
|
||||
- Rule payloads are bare domains: `DOMAIN-SUFFIX,https://qlogo.cn` is invalid.
|
||||
- On a systemd-resolved host, sing-tun normally points resolved at the TUN DNS with `resolvectl`.
|
||||
The nixpkgs `DynamicUser` sandbox cannot make those privileged D-Bus changes, so resolved's own
|
||||
upstream queries bypass `dns-hijack any:53` and leave via the NIC. Tie a resolver takeover to the
|
||||
service lifetime (`resolvectl dns`/`revert` in `ExecStartPost`/`ExecStopPost`, see
|
||||
`hosts/idols-ai/default.nix`), prefixed with `+` to run outside the unit sandbox. Never set link
|
||||
DNS statically to mihomo: a dead mihomo would take DNS down with it, and resolved does not fall
|
||||
back.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -518,7 +518,9 @@ def main [
|
||||
enable: true
|
||||
# port 53 is unreachable here: the unit runs DynamicUser with only
|
||||
# CAP_NET_ADMIN, so a privileged bind fails. TUN's dns-hijack covers
|
||||
# resolution; this listener is a loopback convenience only.
|
||||
# queries that leave through an interface; hosts whose system resolver
|
||||
# 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
|
||||
"enhanced-mode": "fake-ip"
|
||||
|
||||
@@ -11,7 +11,7 @@ in
|
||||
lib.genAttrs hosts (name: {
|
||||
computerUse = true;
|
||||
atspi = true;
|
||||
mihomo = true;
|
||||
mihomo = false;
|
||||
timeZone = "America/Los_Angeles";
|
||||
xvfbRestart = "always";
|
||||
i3Restart = "always";
|
||||
|
||||
Reference in new issue
Block a user