Use the TUN context snapshot in remaining launch-path reads (#9831)

Follow-up to #9830: audit of all TunModeItem.EnableTun usages found
three more launch-path reads of the live mutable config where the
behavior must agree with the context snapshot that generated the
config:

- CoreConfigClashService (mihomo custom config): the tun section was
  decided from the live config while the mihomo launch elevation uses
  the snapshot; a mid-reload toggle could produce a config containing
  tun launched without sudo, the same failure fixed in #9830. The tun
  state is now passed in as a snapshot.
- CoreManager.LoadCore: the Windows RemoveTunDevice cleanup now checks
  the main/pre context snapshots.
- CoreManager.WaitForProxyPort: preContext.AppConfig is a shared live
  reference; use preContext.IsTunEnabled instead.

Reads that intentionally stay live: StatusBarViewModel (UI state
source), CoreConfigContextBuilder (the snapshot capture point),
GetPreSocksItem (called during snapshot construction, self-consistent),
and AppManager.StatePort2 (transient mid-reload skew only, self-heals
after reload).
This commit is contained in:
hyjhyj111
2026-07-27 21:13:28 +08:00
committed by GitHub
parent 611ce0fd2c
commit 02df430172
3 changed files with 9 additions and 7 deletions
@@ -17,7 +17,7 @@ public static class CoreConfigHandler
{ {
result = node.CoreType switch result = node.CoreType switch
{ {
ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName), ECoreType.mihomo => await new CoreConfigClashService(config, context.IsTunEnabled).GenerateClientCustomConfig(node, fileName),
_ => await GenerateClientCustomConfig(node, fileName) _ => await GenerateClientCustomConfig(node, fileName)
}; };
} }
+2 -2
View File
@@ -85,7 +85,7 @@ public class CoreManager
await CoreStop(); await CoreStop();
await Task.Delay(100); await Task.Delay(100);
if (Utils.IsWindows() && _config.TunModeItem.EnableTun) if (Utils.IsWindows() && (mainContext?.IsTunEnabled == true || preContext?.IsTunEnabled == true))
{ {
await Task.Delay(100); await Task.Delay(100);
await WindowsUtils.RemoveTunDevice(); await WindowsUtils.RemoveTunDevice();
@@ -222,7 +222,7 @@ public class CoreManager
{ {
return; return;
} }
if (!preContext.AppConfig.TunModeItem.EnableTun) if (!preContext.IsTunEnabled)
{ {
return; return;
} }
@@ -1,9 +1,11 @@
namespace ServiceLib.Services.CoreConfig; namespace ServiceLib.Services.CoreConfig;
/// <summary> /// <summary>
/// Core configuration file processing class /// Core configuration file processing class.
/// The TUN state is taken as a snapshot so the generated config always agrees
/// with the launch elevation decision (see CoreManager.ShouldRunAsSudo).
/// </summary> /// </summary>
public class CoreConfigClashService(Config config) public class CoreConfigClashService(Config config, bool isTunEnabled)
{ {
private static readonly string _tag = "CoreConfigClashService"; private static readonly string _tag = "CoreConfigClashService";
@@ -102,7 +104,7 @@ public class CoreConfigClashService(Config config)
} }
//enable tun mode //enable tun mode
if (config.TunModeItem.EnableTun) if (isTunEnabled)
{ {
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml); var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
if (tun.IsNotEmpty()) if (tun.IsNotEmpty())
@@ -171,7 +173,7 @@ public class CoreConfigClashService(Config config)
} }
foreach (var item in mixinContent) foreach (var item in mixinContent)
{ {
if (!config.TunModeItem.EnableTun && item.Key == "tun") if (!isTunEnabled && item.Key == "tun")
{ {
continue; continue;
} }