* Fix tun

* Format
This commit is contained in:
DHR60
2026-06-18 02:33:58 +00:00
committed by GitHub
parent be005abf9e
commit 2126ea5a87
@@ -6,8 +6,8 @@ public record CoreConfigContextBuilderResult(CoreConfigContext Context, NodeVali
} }
/// <summary> /// <summary>
/// Holds the results of a full context build, including the main context and an optional /// Holds the results of a full context build, including the main context and an optional
/// pre-socks context (e.g. for TUN protection or pre-socks chaining). /// pre-socks context (e.g. for TUN protection or pre-socks chaining).
/// </summary> /// </summary>
public record CoreConfigContextBuilderAllResult( public record CoreConfigContextBuilderAllResult(
CoreConfigContextBuilderResult MainResult, CoreConfigContextBuilderResult MainResult,
@@ -17,8 +17,8 @@ public record CoreConfigContextBuilderAllResult(
public bool Success => MainResult.Success && (PreSocksResult?.Success ?? true); public bool Success => MainResult.Success && (PreSocksResult?.Success ?? true);
/// <summary> /// <summary>
/// Merges all errors and warnings from the main result and the optional pre-socks result /// Merges all errors and warnings from the main result and the optional pre-socks result
/// into a single <see cref="NodeValidatorResult"/> for unified notification. /// into a single <see cref="NodeValidatorResult" /> for unified notification.
/// </summary> /// </summary>
public NodeValidatorResult CombinedValidatorResult => new( public NodeValidatorResult CombinedValidatorResult => new(
[.. MainResult.ValidatorResult.Errors, .. PreSocksResult?.ValidatorResult.Errors ?? []], [.. MainResult.ValidatorResult.Errors, .. PreSocksResult?.ValidatorResult.Errors ?? []],
@@ -28,14 +28,14 @@ public record CoreConfigContextBuilderAllResult(
public class CoreConfigContextBuilder public class CoreConfigContextBuilder
{ {
/// <summary> /// <summary>
/// Builds a <see cref="CoreConfigContext"/> for the given node, resolves its proxy map, /// Builds a <see cref="CoreConfigContext" /> for the given node, resolves its proxy map,
/// and processes outbound nodes referenced by routing rules. /// and processes outbound nodes referenced by routing rules.
/// </summary> /// </summary>
public static async Task<CoreConfigContextBuilderResult> Build(Config config, ProfileItem node) public static async Task<CoreConfigContextBuilderResult> Build(Config config, ProfileItem node)
{ {
var runCoreType = AppManager.Instance.GetCoreType(node, node.ConfigType); var runCoreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
var coreType = runCoreType == ECoreType.sing_box ? ECoreType.sing_box : ECoreType.Xray; var coreType = runCoreType == ECoreType.sing_box ? ECoreType.sing_box : ECoreType.Xray;
var context = new CoreConfigContext() var context = new CoreConfigContext
{ {
Node = node, Node = node,
RunCoreType = runCoreType, RunCoreType = runCoreType,
@@ -61,7 +61,8 @@ public class CoreConfigContextBuilder
if (!(context.RoutingItem?.RuleSet.IsNullOrEmpty() ?? true)) if (!(context.RoutingItem?.RuleSet.IsNullOrEmpty() ?? true))
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(context.RoutingItem?.RuleSet) ?? []; var rules = JsonUtils.Deserialize<List<RulesItem>>(context.RoutingItem?.RuleSet) ?? [];
foreach (var ruleItem in rules.Where(ruleItem => ruleItem.Enabled && !Global.OutboundTags.Contains(ruleItem.OutboundTag))) foreach (var ruleItem in rules.Where(ruleItem =>
ruleItem.Enabled && !Global.OutboundTags.Contains(ruleItem.OutboundTag)))
{ {
if (ruleItem.OutboundTag.IsNullOrEmpty()) if (ruleItem.OutboundTag.IsNullOrEmpty())
{ {
@@ -72,7 +73,8 @@ public class CoreConfigContextBuilder
var ruleOutboundNode = await AppManager.Instance.GetProfileItemViaRemarks(ruleItem.OutboundTag); var ruleOutboundNode = await AppManager.Instance.GetProfileItemViaRemarks(ruleItem.OutboundTag);
if (ruleOutboundNode == null) if (ruleOutboundNode == null)
{ {
validatorResult.Warnings.Add(string.Format(ResUI.MsgRoutingRuleOutboundNodeNotFound, ruleItem.Remarks, ruleItem.OutboundTag)); validatorResult.Warnings.Add(string.Format(ResUI.MsgRoutingRuleOutboundNodeNotFound,
ruleItem.Remarks, ruleItem.OutboundTag));
ruleItem.OutboundTag = Global.ProxyTag; ruleItem.OutboundTag = Global.ProxyTag;
continue; continue;
} }
@@ -83,7 +85,8 @@ public class CoreConfigContextBuilder
if (!ruleNodeValidatorResult.Success) if (!ruleNodeValidatorResult.Success)
{ {
validatorResult.Warnings.AddRange(ruleNodeValidatorResult.Errors.Select(e => validatorResult.Warnings.AddRange(ruleNodeValidatorResult.Errors.Select(e =>
string.Format(ResUI.MsgRoutingRuleOutboundNodeError, ruleItem.Remarks, ruleItem.OutboundTag, e))); string.Format(ResUI.MsgRoutingRuleOutboundNodeError, ruleItem.Remarks, ruleItem.OutboundTag,
e)));
ruleItem.OutboundTag = Global.ProxyTag; ruleItem.OutboundTag = Global.ProxyTag;
continue; continue;
} }
@@ -110,9 +113,9 @@ public class CoreConfigContextBuilder
} }
/// <summary> /// <summary>
/// Builds the main <see cref="CoreConfigContext"/> for <paramref name="node"/> and, when /// Builds the main <see cref="CoreConfigContext" /> for <paramref name="node" /> and, when
/// the main build succeeds, also builds the optional pre-socks context required for TUN /// the main build succeeds, also builds the optional pre-socks context required for TUN
/// protection or pre-socks proxy chaining. /// protection or pre-socks proxy chaining.
/// </summary> /// </summary>
public static async Task<CoreConfigContextBuilderAllResult> BuildAll(Config config, ProfileItem node) public static async Task<CoreConfigContextBuilderAllResult> BuildAll(Config config, ProfileItem node)
{ {
@@ -132,16 +135,31 @@ public class CoreConfigContextBuilder
{ {
Context = mainResult.Context with Context = mainResult.Context with
{ {
IsTunEnabled = false, // main core doesn't handle tun directly when pre-socks is used IsTunEnabled = false,
// main core doesn't handle tun directly when pre-socks is used
ProtectDomainList = [.. mainResult.Context.ProtectDomainList, .. preResult.Context.ProtectDomainList], ProtectDomainList = [.. mainResult.Context.ProtectDomainList, .. preResult.Context.ProtectDomainList],
} },
}; };
if (mainResult.Context.IsTunEnabled
&& mainResult.Context.AppConfig.TunModeItem.StrictRoute)
{
var appConfig = JsonUtils.DeepCopy(mainResult.Context.AppConfig);
appConfig.CoreBasicItem.BindInterface = string.Empty;
appConfig.CoreBasicItem.SendThrough = string.Empty;
resolvedMainResult = resolvedMainResult with
{
Context = resolvedMainResult.Context with
{
AppConfig = appConfig,
},
};
}
return new CoreConfigContextBuilderAllResult(resolvedMainResult, preResult); return new CoreConfigContextBuilderAllResult(resolvedMainResult, preResult);
} }
/// <summary> /// <summary>
/// Determines whether a pre-socks context is required for <paramref name="nodeContext"/> /// Determines whether a pre-socks context is required for <paramref name="nodeContext" />
/// and, if so, builds and returns it. Returns <c>null</c> when no pre-socks core is needed. /// and, if so, builds and returns it. Returns <c>null</c> when no pre-socks core is needed.
/// </summary> /// </summary>
private static async Task<CoreConfigContextBuilderResult?> BuildPreSocksIfNeeded(CoreConfigContext nodeContext) private static async Task<CoreConfigContextBuilderResult?> BuildPreSocksIfNeeded(CoreConfigContext nodeContext)
{ {
@@ -157,8 +175,9 @@ public class CoreConfigContextBuilder
{ {
Context = preSocksResult.Context with Context = preSocksResult.Context with
{ {
ProtectDomainList = [.. nodeContext.ProtectDomainList ?? [], .. preSocksResult.Context.ProtectDomainList ?? []], ProtectDomainList =
} [.. nodeContext.ProtectDomainList ?? [], .. preSocksResult.Context.ProtectDomainList ?? []],
},
}; };
} }
@@ -166,8 +185,8 @@ public class CoreConfigContextBuilder
} }
/// <summary> /// <summary>
/// Resolves a node into the context, optionally wrapping it in a subscription-level proxy chain. /// Resolves a node into the context, optionally wrapping it in a subscription-level proxy chain.
/// Returns the effective (possibly replaced) node and the validation result. /// Returns the effective (possibly replaced) node and the validation result.
/// </summary> /// </summary>
public static async Task<(ProfileItem, NodeValidatorResult)> ResolveNodeAsync(CoreConfigContext context, public static async Task<(ProfileItem, NodeValidatorResult)> ResolveNodeAsync(CoreConfigContext context,
ProfileItem node, ProfileItem node,
@@ -202,12 +221,13 @@ public class CoreConfigContextBuilder
} }
/// <summary> /// <summary>
/// If the node's subscription defines prev/next profiles, creates a virtual /// If the node's subscription defines prev/next profiles, creates a virtual
/// <see cref="EConfigType.ProxyChain"/> node that wraps them together. /// <see cref="EConfigType.ProxyChain" /> node that wraps them together.
/// Returns <c>null</c> as the chain item when no chain is needed. /// Returns <c>null</c> as the chain item when no chain is needed.
/// Any warnings (e.g. missing prev/next profile) are returned in the validator result. /// Any warnings (e.g. missing prev/next profile) are returned in the validator result.
/// </summary> /// </summary>
private static async Task<(ProfileItem? ChainNode, NodeValidatorResult ValidatorResult)> BuildSubscriptionChainNodeAsync(ProfileItem node) private static async Task<(ProfileItem? ChainNode, NodeValidatorResult ValidatorResult)>
BuildSubscriptionChainNodeAsync(ProfileItem node)
{ {
var result = NodeValidatorResult.Empty(); var result = NodeValidatorResult.Empty();
@@ -248,7 +268,7 @@ public class CoreConfigContextBuilder
} }
// Build new proxy chain node // Build new proxy chain node
var chainNode = new ProfileItem() var chainNode = new ProfileItem
{ {
IndexId = $"inner-{Utils.GetGuid(false)}", IndexId = $"inner-{Utils.GetGuid(false)}",
ConfigType = EConfigType.ProxyChain, ConfigType = EConfigType.ProxyChain,
@@ -266,8 +286,8 @@ public class CoreConfigContextBuilder
} }
/// <summary> /// <summary>
/// Dispatches registration to either <see cref="RegisterGroupNodeAsync"/> or /// Dispatches registration to either <see cref="RegisterGroupNodeAsync" /> or
/// <see cref="RegisterSingleNodeAsync"/> based on the node's config type. /// <see cref="RegisterSingleNodeAsync" /> based on the node's config type.
/// </summary> /// </summary>
private static async Task<NodeValidatorResult> RegisterNodeAsync(CoreConfigContext context, ProfileItem node) private static async Task<NodeValidatorResult> RegisterNodeAsync(CoreConfigContext context, ProfileItem node)
{ {
@@ -275,15 +295,12 @@ public class CoreConfigContextBuilder
{ {
return await RegisterGroupNodeAsync(context, node); return await RegisterGroupNodeAsync(context, node);
} }
else return RegisterSingleNodeAsync(context, node);
{
return RegisterSingleNodeAsync(context, node);
}
} }
/// <summary> /// <summary>
/// Validates a single (non-group) node and, on success, adds it to the proxy map /// Validates a single (non-group) node and, on success, adds it to the proxy map
/// and records any domain addresses that should bypass the proxy. /// and records any domain addresses that should bypass the proxy.
/// </summary> /// </summary>
private static NodeValidatorResult RegisterSingleNodeAsync(CoreConfigContext context, ProfileItem node) private static NodeValidatorResult RegisterSingleNodeAsync(CoreConfigContext context, ProfileItem node)
{ {
@@ -347,8 +364,8 @@ public class CoreConfigContextBuilder
} }
/// <summary> /// <summary>
/// Entry point for registering a group node. Initialises the visited/ancestor sets /// Entry point for registering a group node. Initialises the visited/ancestor sets
/// and delegates to <see cref="TraverseGroupNodeAsync"/>. /// and delegates to <see cref="TraverseGroupNodeAsync" />.
/// </summary> /// </summary>
private static async Task<NodeValidatorResult> RegisterGroupNodeAsync(CoreConfigContext context, private static async Task<NodeValidatorResult> RegisterGroupNodeAsync(CoreConfigContext context,
ProfileItem node) ProfileItem node)
@@ -364,9 +381,9 @@ public class CoreConfigContextBuilder
} }
/// <summary> /// <summary>
/// Recursively walks the children of a group node, registering valid leaf nodes /// Recursively walks the children of a group node, registering valid leaf nodes
/// and nested groups. Detects cycles via <paramref name="ancestorsGroup"/> and /// and nested groups. Detects cycles via <paramref name="ancestorsGroup" /> and
/// deduplicates shared nodes via <paramref name="globalVisitedGroup"/>. /// deduplicates shared nodes via <paramref name="globalVisitedGroup" />.
/// </summary> /// </summary>
private static async Task<NodeValidatorResult> TraverseGroupNodeAsync( private static async Task<NodeValidatorResult> TraverseGroupNodeAsync(
CoreConfigContext context, CoreConfigContext context,
@@ -430,13 +447,10 @@ public class CoreConfigContextBuilder
childNodeValidatorResult.Errors.Add(string.Format(ResUI.MsgGroupNoValidChildNode, node.Remarks)); childNodeValidatorResult.Errors.Add(string.Format(ResUI.MsgGroupNoValidChildNode, node.Remarks));
return childNodeValidatorResult; return childNodeValidatorResult;
} }
else childNodeValidatorResult.Warnings.AddRange(childNodeValidatorResult.Errors);
{ childNodeValidatorResult.Errors.Clear();
childNodeValidatorResult.Warnings.AddRange(childNodeValidatorResult.Errors);
childNodeValidatorResult.Errors.Clear();
}
node.SetProtocolExtra(node.GetProtocolExtra() with { ChildItems = Utils.List2String(childIndexIdList), }); node.SetProtocolExtra(node.GetProtocolExtra() with { ChildItems = Utils.List2String(childIndexIdList) });
context.AllProxiesMap[node.IndexId] = node; context.AllProxiesMap[node.IndexId] = node;
return childNodeValidatorResult; return childNodeValidatorResult;
} }