mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:46 +01:00
fix(shoukei): route DNS through the mihomo TUN
Assisted-by: DeepSeek Harness (gpt-6-astra)
This commit is contained in:
1 parent
bac43e0e9f
commit
b24f30c38c
5 files changed
+87
-3
No files matched your search
@@ -51,6 +51,8 @@ in
|
||||
inherit (myvars.networking) nameservers;
|
||||
};
|
||||
|
||||
modules.networking.mihomo.resolvedIntegration = true;
|
||||
|
||||
fileSystems."/btr_pool" = {
|
||||
device = "/dev/disk/by-uuid/c2e8b249-240e-4eef-bf4e-81e7dbbf4887";
|
||||
fsType = "btrfs";
|
||||
|
||||
@@ -138,6 +138,17 @@ targets instead of writing a config the core rejects.
|
||||
`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.
|
||||
- On shoukei, `modules.networking.mihomo.resolvedIntegration` enables resolved and the
|
||||
NetworkManager resolved backend. Once DNS is listening, the service registers `127.0.0.1:1053` and
|
||||
`~.` on `Meta`, which NetworkManager leaves unmanaged. Wi-Fi reconnects can update their own DNS
|
||||
without overwriting this route. Stopping mihomo reverts only `Meta`; removing the TUN also removes
|
||||
its DNS configuration, leaving the physical links' DNS available. More-specific VPN DNS routes
|
||||
still win; another VPN claiming `~.` (including Tailscale's full DNS override) would share the
|
||||
catch-all and must not be used concurrently. This relies on mihomo's default `Meta` device name
|
||||
and the generator's local DNS port; apply TUN changes with a service restart so the DNS hook runs
|
||||
for the new interface. After activation, verify normal and reconnected Wi-Fi queries return fake
|
||||
IPs, and that stopping mihomo restores network DNS. See
|
||||
[systemd's VPN DNS routing guide](https://github.com/systemd/systemd/blob/main/docs/RESOLVED-VPNS.md).
|
||||
|
||||
## Steam download region
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@ let
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.modules.networking.mihomo.enable =
|
||||
lib.mkEnableOption "the native Mihomo core with TUN and a local web UI";
|
||||
options.modules.networking.mihomo = {
|
||||
enable = lib.mkEnableOption "the native Mihomo core with TUN and a local web UI";
|
||||
resolvedIntegration = lib.mkEnableOption "route systemd-resolved DNS through the mihomo TUN interface";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.mihomo = {
|
||||
@@ -67,10 +69,56 @@ in
|
||||
# and fail with "Failed to set up credentials: No such file or directory".
|
||||
systemd.services.mihomo.unitConfig.RequiresMountsFor = builtins.dirOf configFile;
|
||||
|
||||
services.resolved.enable = lib.mkIf cfg.resolvedIntegration true;
|
||||
networking.networkmanager =
|
||||
lib.mkIf (cfg.resolvedIntegration && config.networking.networkmanager.enable)
|
||||
{
|
||||
dns = "systemd-resolved";
|
||||
# NetworkManager owns physical links; mihomo owns this virtual link.
|
||||
unmanaged = [ "interface-name:Meta" ];
|
||||
};
|
||||
systemd.services.mihomo.after = lib.optional cfg.resolvedIntegration "systemd-resolved.service";
|
||||
systemd.services.mihomo.requires = lib.optional cfg.resolvedIntegration "systemd-resolved.service";
|
||||
|
||||
# Force the TUN's v6 address up: left to itself mihomo skips the v6 half when
|
||||
# no NIC has an IPv6 address at startup, yet still installs its strict-route v6
|
||||
# blackhole, which locks the host out of IPv6. Upstream knob (`inet6-address`,
|
||||
# meta-docs tun.md); the full chain is WA-030.
|
||||
systemd.services.mihomo.serviceConfig.Environment = [ "SKIP_SYSTEM_IPV6_CHECK=1" ];
|
||||
systemd.services.mihomo.serviceConfig = {
|
||||
Environment = [ "SKIP_SYSTEM_IPV6_CHECK=1" ];
|
||||
}
|
||||
// lib.optionalAttrs cfg.resolvedIntegration {
|
||||
# Attach the catch-all to the TUN, leaving DHCP and more-specific VPN DNS
|
||||
# routes untouched. Removing the TUN also removes its resolved settings.
|
||||
# '+' allows the privileged D-Bus call outside mihomo's service sandbox.
|
||||
ExecStartPost = "+${pkgs.coreutils}/bin/timeout 30 ${
|
||||
lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "mihomo-resolved";
|
||||
runtimeInputs = [
|
||||
pkgs.dig
|
||||
pkgs.systemd
|
||||
];
|
||||
text = ''
|
||||
until (( SECONDS >= 25 )); do
|
||||
if [[ -e /sys/class/net/Meta ]] \
|
||||
&& dig +time=1 +tries=1 @127.0.0.1 -p 1053 localhost A >/dev/null \
|
||||
&& resolvectl dns Meta 127.0.0.1:1053 \
|
||||
&& resolvectl dnssec Meta no \
|
||||
&& resolvectl dnsovertls Meta no \
|
||||
&& resolvectl domain Meta '~.'; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
echo "mihomo TUN or DNS did not become ready" >&2
|
||||
exit 1
|
||||
'';
|
||||
}
|
||||
)
|
||||
}";
|
||||
# The interface may already be gone after a clean stop or a crash.
|
||||
ExecStopPost = "-+${pkgs.systemd}/bin/resolvectl revert Meta";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
resolved = true;
|
||||
resolvconf = false;
|
||||
dnsBackend = "systemd-resolved";
|
||||
tunUnmanaged = true;
|
||||
dispatcherCount = 0;
|
||||
resolverOrdered = true;
|
||||
resolverRequired = true;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{ outputs, ... }:
|
||||
let
|
||||
system = outputs.nixosConfigurations.shoukei-niri.config;
|
||||
nm = system.networking.networkmanager;
|
||||
in
|
||||
{
|
||||
resolved = system.services.resolved.enable;
|
||||
resolvconf = system.networking.resolvconf.enable;
|
||||
dnsBackend = nm.dns;
|
||||
tunUnmanaged = builtins.elem "interface-name:Meta" nm.unmanaged;
|
||||
dispatcherCount = builtins.length nm.dispatcherScripts;
|
||||
resolverOrdered = builtins.elem "systemd-resolved.service" system.systemd.services.mihomo.after;
|
||||
resolverRequired = builtins.elem "systemd-resolved.service" system.systemd.services.mihomo.requires;
|
||||
}
|
||||
Reference in new issue
Block a user