From 8c5b7dd56659f5003d9c3eef8b90b66a92d251ed Mon Sep 17 00:00:00 2001 From: bazhuang Date: Thu, 21 May 2026 15:09:08 +0800 Subject: [PATCH] fix no-resolve rule-missing-target --- lib/common/task.dart | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lib/common/task.dart b/lib/common/task.dart index a8e0c298b7..5dfa1364a7 100644 --- a/lib/common/task.dart +++ b/lib/common/task.dart @@ -73,6 +73,43 @@ Future> _toGroupsTask(ComputeGroupsState state) async { ); } +const _ruleParams = {'no-resolve', 'src'}; + +/// Fixes rules that are missing a TARGET field. +/// +/// Some subscription sources produce rules like `IP-CIDR,192.133.76.0/22,no-resolve` +/// where `no-resolve` is a parameter but the TARGET (proxy name) is missing. +/// This inserts a default TARGET to prevent mihomo from treating the parameter +/// as a proxy name. +List _fixRules(List rules) { + String defaultTarget = 'DIRECT'; + for (final rule in rules.reversed) { + final parts = rule.split(','); + final nonParams = parts.where((p) => !_ruleParams.contains(p)).toList(); + if (nonParams.isNotEmpty && nonParams.first == 'MATCH') { + if (nonParams.length >= 2 && nonParams.last.isNotEmpty) { + defaultTarget = nonParams.last; + } + break; + } + } + + return rules.map((rule) { + final parts = rule.split(','); + final nonParams = parts.where((p) => !_ruleParams.contains(p)).toList(); + if (nonParams.length < 2) return rule; + final first = nonParams.first; + final isMatch = first == 'MATCH'; + final isSubRule = first == 'SUB-RULE'; + if (isMatch || isSubRule) return rule; + // A well-formed rule has at least: TYPE, CONTENT, TARGET (3 non-param parts) + if (nonParams.length >= 3) return rule; + // Missing TARGET: nonParams is [TYPE, CONTENT]. Insert defaultTarget. + final params = parts.where((p) => _ruleParams.contains(p)).toList(); + return [...nonParams, defaultTarget, ...params].join(','); + }).toList(); +} + Future> makeRealProfileTask( MakeRealProfileState data, ) async { @@ -214,6 +251,7 @@ Future> _makeRealProfileTask( rules = List.from(rawConfig['rules']); } rawConfig.remove('rules'); + rules = _fixRules(rules); if (addedRules.isNotEmpty) { final parsedNewRules = addedRules .map((item) => ParsedRule.parseString(item.value))