Compare commits

..

10 Commits

Author SHA1 Message Date
2dust
c0aa829abb up 7.19.2 2026-03-05 09:49:46 +08:00
DHR60
b8f7cc0768 Fix hosts matching (#8890)
* Fix hosts matching

* Fix hosts resolve rule

* Fix
2026-03-04 20:13:06 +08:00
2dust
81da72bb39 Fix
https://github.com/2dust/v2rayN/issues/8881
2026-03-04 19:11:31 +08:00
2dust
d9201157c8 Bug fix
https://github.com/2dust/v2rayN/issues/8875
2026-03-04 18:58:59 +08:00
2dust
e179d5bc42 Fix
https://github.com/2dust/v2rayN/issues/8870
2026-03-03 16:03:23 +08:00
2dust
4d2f32099e Bug fix
https://github.com/2dust/v2rayN/issues/8879
2026-03-03 10:07:48 +08:00
2dust
f24a79aa2c Bug fix
https://github.com/2dust/v2rayN/issues/8875
2026-03-02 20:18:07 +08:00
2dust
9a3604e89b Bug fix
https://github.com/2dust/v2rayN/issues/8874
2026-03-02 20:00:02 +08:00
DHR60
fd7cf0d453 Fix xray custom dns (#8872) 2026-03-02 19:46:01 +08:00
tt2563
65cf782eb0 更新繁體中文翻譯 (#8873)
Co-authored-by: ertet <sfsa@sdaf.cc>
2026-03-02 19:44:53 +08:00
9 changed files with 180 additions and 87 deletions

View File

@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Version>7.19.1</Version>
<Version>7.19.2</Version>
</PropertyGroup>
<PropertyGroup>

View File

@@ -231,6 +231,7 @@ public static class ConfigHandler
item.Address = profileItem.Address;
item.Port = profileItem.Port;
item.Username = profileItem.Username;
item.Password = profileItem.Password;
item.Network = profileItem.Network;
@@ -1331,6 +1332,7 @@ public static class ConfigHandler
public static async Task<int> RemoveInvalidServerResult(Config config, string subid)
{
var lstModel = await AppManager.Instance.ProfileModels(subid, "");
lstModel.RemoveAll(t => t.ConfigType.IsComplexType());
if (lstModel is { Count: <= 0 })
{
return -1;

View File

@@ -28,6 +28,7 @@ public class Dns4Sbox
public bool? disable_cache { get; set; }
public bool? disable_expire { get; set; }
public bool? independent_cache { get; set; }
public int? cache_capacity { get; set; }
public bool? reverse_mapping { get; set; }
public string? client_subnet { get; set; }
}

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value>
</data>
<data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改偵聽埠。</value>
<value>注意,自訂設定完全依賴您自行輸入的內容,部分功能可能無法使用。如需用系統代理請手動調整監聽埠。</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>下載開始...</value>
@@ -139,7 +139,7 @@
<value>生成預設設定檔失敗</value>
</data>
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
<value>取預設設定失敗</value>
<value>取預設設定失敗</value>
</data>
<data name="FailedImportedCustomServer" xml:space="preserve">
<value>匯入自訂設定失敗</value>
@@ -148,7 +148,7 @@
<value>讀取設定失敗</value>
</data>
<data name="FillCorrectServerPort" xml:space="preserve">
<value>請填寫正確格式的埠</value>
<value>請填寫有效的埠</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機偵聽埠</value>
@@ -247,7 +247,7 @@
<value>非 VMess 或 SS 協定</value>
</data>
<data name="NotFoundCore" xml:space="preserve">
<value>在資料夾 ({0}) 下未找到 Core 檔案 (檔案名: {1})請下載後放入資料夾下載網址: {2}</value>
<value>在資料夾 ({0}) 中找不到 Core 檔案(檔名:{1})。請下載後放入資料夾下載網址{2}</value>
</data>
<data name="NoValidQRcodeFound" xml:space="preserve">
<value>掃描完成,未發現有效二維碼</value>
@@ -304,7 +304,7 @@
<value>是否確定移除規則?</value>
</data>
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
<value>{0}必填其中一項.</value>
<value>{0}至少需填寫其中一項</value>
</data>
<data name="LvRemarks" xml:space="preserve">
<value>別名</value>
@@ -385,7 +385,7 @@
<value>所有</value>
</data>
<data name="FillServerAddressCustom" xml:space="preserve">
<value>請瀏覽匯入設定</value>
<value>請選擇要匯入設定</value>
</data>
<data name="Speedtesting" xml:space="preserve">
<value>測試中...</value>
@@ -472,7 +472,7 @@
<value>語言 (需重啟)</value>
</data>
<data name="menuAddServerViaClipboard" xml:space="preserve">
<value>從剪貼簿入分享連結</value>
<value>從剪貼簿入分享連結</value>
</data>
<data name="menuAddServerViaScan" xml:space="preserve">
<value>掃描螢幕上的二維碼</value>
@@ -616,10 +616,10 @@
<value>SNI</value>
</data>
<data name="TbStreamSecurity" xml:space="preserve">
<value>傳輸層安全 (TLS)</value>
<value>傳輸層安全 (TLS)</value>
</data>
<data name="TipNetwork" xml:space="preserve">
<value>*預設 TCP選錯會無法連</value>
<value>*預設 TCP選錯會無法連</value>
</data>
<data name="TbCoreType" xml:space="preserve">
<value>Core 類型</value>
@@ -652,7 +652,7 @@
<value>SOCKS 埠</value>
</data>
<data name="TipPreSocksPort" xml:space="preserve">
<value>*自訂設定的 Socks 埠值,可不設定;當設定此值後,將使用 Xray/sing-box (Tun) 額外啟動一個前置 Socks 服務,提供分流和速度顯示等功能</value>
<value>*自訂設定的 Socks 埠值,可留空;當設定此值後,將使用 Xray/sing-box (Tun) 額外啟動一個前置 Socks 服務,提供分流和速度顯示等功能</value>
</data>
<data name="TbBrowse" xml:space="preserve">
<value>瀏覽</value>
@@ -1309,7 +1309,7 @@
<value>安裝字體到系統中,選擇或填入字體名稱,重新啟動後生效</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>是否確定退出?</value>
<value>確定退出</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>備註備忘</value>
@@ -1495,13 +1495,13 @@
<value>策略組類型</value>
</data>
<data name="menuAddPolicyGroupServer" xml:space="preserve">
<value>添加策略組</value>
<value>新增策略組</value>
</data>
<data name="menuAddProxyChainServer" xml:space="preserve">
<value>添加鏈式代理</value>
<value>新增鏈式代理</value>
</data>
<data name="menuAddChildServer" xml:space="preserve">
<value>添加子配置</value>
<value>新增子配置</value>
</data>
<data name="menuRemoveChildServer" xml:space="preserve">
<value>刪除子配置</value>
@@ -1591,81 +1591,81 @@
<value>EchForceQuery</value>
</data>
<data name="TbFullCertTips" xml:space="preserve">
<value>Full certificate (chain), PEM format</value>
<value>完整憑證PEM 格式</value>
</data>
<data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value>
<value>憑證指紋(SHA-256</value>
</data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
<value>提供過期快取(Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
<value>并行查詢</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
<value>預設僅在路由期間進行解析時調用</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
<value>預設僅在路由期間進行解析時調用;請確保遠端伺服器能連線至此 DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
<value>若未設定或為 "AsIs",使用系統 DNS 解析;否則將使用內建 DNS 模組。</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
<value>若未設定或為 "AsIs",由遠端伺服器的 DNS 解析;否則將使用內建 DNS 模組。</value>
</data>
<data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value>
<value>連接埠跳轉間隔</value>
</data>
<data name="menuServerListPreview" xml:space="preserve">
<value>Configuration item preview</value>
<value>子配置項預覽</value>
</data>
<data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value>
</data>
<data name="MsgRoutingRuleOutboundNodeWarning" xml:space="preserve">
<value>Routing rule {0} outbound node {1} warning: {2}</value>
<value>路由規則 {0} 的出站節點 {1} 發出警告:{2}</value>
</data>
<data name="MsgRoutingRuleOutboundNodeError" xml:space="preserve">
<value>Routing rule {0} outbound node {1} error: {2}. Fallback to proxy node only.</value>
<value>路由規則 {0} 的出站節點 {1} 發生錯誤:{2}。已回退為僅使用代理節點。</value>
</data>
<data name="MsgGroupCycleDependency" xml:space="preserve">
<value>Group {0} has a cycle dependency on child node {1}. Skipping this node.</value>
<value>節點組 {0} 與子節點 {1} 存在循環依賴。已跳過此節點。</value>
</data>
<data name="MsgGroupChildNodeWarning" xml:space="preserve">
<value>Group {0} child node {1} warning: {2}</value>
<value>節點組 {0} 的子節點 {1} 發出警告:{2}</value>
</data>
<data name="MsgGroupChildNodeError" xml:space="preserve">
<value>Group {0} child node {1} error: {2}. Skipping this node.</value>
<value>節點組 {0} 的子節點 {1} 發生錯誤:{2}。已跳過此節點。</value>
</data>
<data name="MsgGroupChildGroupNodeWarning" xml:space="preserve">
<value>Group {0} child group node {1} warning: {2}</value>
<value>節點組 {0} 的子節點組 {1} 發出警告:{2}</value>
</data>
<data name="MsgGroupChildGroupNodeError" xml:space="preserve">
<value>Group {0} child group node {1} error: {2}. Skipping this node.</value>
<value>節點組 {0} 的子節點組 {1} 發生錯誤:{2}。已跳過此節點。</value>
</data>
<data name="MsgGroupNoValidChildNode" xml:space="preserve">
<value>Group {0} has no valid child node.</value>
<value>節點組 {0} 沒有可用的有效子節點。</value>
</data>
<data name="MsgRoutingRuleEmptyOutboundTag" xml:space="preserve">
<value>Routing rule {0} has an empty outbound tag. Fallback to proxy node only.</value>
<value>路由規則 {0} 的出站標籤為空。已回退為僅使用代理節點。</value>
</data>
<data name="MsgRoutingRuleOutboundNodeNotFound" xml:space="preserve">
<value>Routing rule {0} outbound node {1} not found. Fallback to proxy node only.</value>
<value>找不到路由規則 {0} 的出站節點 {1}。已回退為僅使用代理節點。</value>
</data>
<data name="MsgSubscriptionPrevProfileNotFound" xml:space="preserve">
<value>Subscription previous proxy {0} not found. Skipping.</value>
<value>找不到訂閱的前一個代理 {0}。已跳過。</value>
</data>
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
<value>Subscription next proxy {0} not found. Skipping.</value>
<value>找不到訂閱的下一個代理 {0}。已跳過。</value>
</data>
<data name="menuGenGroupServer" xml:space="preserve">
<value>Generate Policy Group</value>
<value>生成策略組</value>
</data>
<data name="menuAllServers" xml:space="preserve">
<value>All configurations</value>
<value>所有配置項</value>
</data>
<data name="menuGenRegionGroup" xml:space="preserve">
<value>Group by Region</value>
<value>按區域分組</value>
</data>
</root>

View File

@@ -93,7 +93,23 @@ public partial class CoreConfigSingboxService
foreach (var kvp in Utils.ParseHostsToDictionary(simpleDnsItem.Hosts))
{
hostsDns.predefined[kvp.Key] = kvp.Value.Where(Utils.IsIpAddress).ToList();
// only allow full match
// like example.com and full:example.com,
// but not domain:example.com, keyword:example.com or regex:example.com etc.
var testRule = new Rule4Sbox();
if (!ParseV2Domain(kvp.Key, testRule))
{
continue;
}
if (testRule.domain_keyword?.Count > 0 && !kvp.Key.Contains(':'))
{
testRule.domain = testRule.domain_keyword;
testRule.domain_keyword = null;
}
if (testRule.domain?.Count == 1)
{
hostsDns.predefined[testRule.domain.First()] = kvp.Value.Where(Utils.IsIpAddress).ToList();
}
}
foreach (var host in hostsDns.predefined)
@@ -179,44 +195,66 @@ public partial class CoreConfigSingboxService
foreach (var kvp in Utils.ParseHostsToDictionary(simpleDnsItem.Hosts))
{
var predefined = kvp.Value.First();
if (predefined.IsNullOrEmpty() || Utils.IsIpAddress(predefined))
if (predefined.IsNullOrEmpty())
{
continue;
}
if (predefined.StartsWith('#') && int.TryParse(predefined.AsSpan(1), out var rcode))
var rule = new Rule4Sbox()
{
// xray syntactic sugar for predefined
// etc. #0 -> NOERROR
_coreConfig.dns.rules.Add(new()
{
query_type = [1, 28],
domain = [kvp.Key],
action = "predefined",
rcode = rcode switch
{
0 => "NOERROR",
1 => "FORMERR",
2 => "SERVFAIL",
3 => "NXDOMAIN",
4 => "NOTIMP",
5 => "REFUSED",
_ => "NOERROR",
},
});
continue;
}
// CNAME record
Rule4Sbox rule = new()
{
query_type = [1, 28],
query_type = [1, 5, 28], // A, CNAME and AAAA
action = "predefined",
rcode = "NOERROR",
answer = [$"*. IN CNAME {predefined}."],
};
if (ParseV2Domain(kvp.Key, rule))
if (!ParseV2Domain(kvp.Key, rule))
{
_coreConfig.dns.rules.Add(rule);
continue;
}
// see: https://xtls.github.io/en/config/dns.html#dnsobject
// The matching format (domain:, full:, etc.) is the same as the domain
// in the commonly used Routing System. The difference is that without a prefix,
// it defaults to using the full: prefix (similar to the common hosts file syntax).
if (rule.domain_keyword?.Count > 0 && !kvp.Key.Contains(':'))
{
rule.domain = rule.domain_keyword;
rule.domain_keyword = null;
}
// example.com #0 -> example.com with NOERROR
if (predefined.StartsWith('#') && int.TryParse(predefined.AsSpan(1), out var rcode))
{
rule.rcode = rcode switch
{
0 => "NOERROR",
1 => "FORMERR",
2 => "SERVFAIL",
3 => "NXDOMAIN",
4 => "NOTIMP",
5 => "REFUSED",
_ => "NOERROR",
};
}
else if (Utils.IsDomain(predefined))
{
// example.com CNAME target.com -> example.com with CNAME target.com
rule.answer = new List<string> { $"*. IN CNAME {predefined}." };
}
else if (Utils.IsIpAddress(predefined) && (rule.domain?.Count ?? 0) == 0)
{
// not full match, but an IP address, treat it as predefined answer
if (Utils.IsIpv6(predefined))
{
rule.answer = new List<string> { $"*. IN AAAA {predefined}" };
}
else
{
rule.answer = new List<string> { $"*. IN A {predefined}" };
}
}
else
{
continue;
}
_coreConfig.dns.rules.Add(rule);
}
if (simpleDnsItem.BlockBindingQuery == true)

View File

@@ -84,11 +84,58 @@ public partial class CoreConfigSingboxService
}
if (hostsDomains.Count > 0)
{
_coreConfig.route.rules.Add(new()
var hostsResolveRule = new Rule4Sbox
{
action = "resolve",
domain = hostsDomains,
});
};
var hostsCounter = 0;
foreach (var host in hostsDomains)
{
var domainRule = new Rule4Sbox();
if (!ParseV2Domain(host, domainRule))
{
continue;
}
if (domainRule.domain_keyword?.Count > 0 && !host.Contains(':'))
{
domainRule.domain = domainRule.domain_keyword;
domainRule.domain_keyword = null;
}
if (domainRule.domain?.Count > 0)
{
hostsResolveRule.domain ??= [];
hostsResolveRule.domain.AddRange(domainRule.domain);
hostsCounter++;
}
else if (domainRule.domain_keyword?.Count > 0)
{
hostsResolveRule.domain_keyword ??= [];
hostsResolveRule.domain_keyword.AddRange(domainRule.domain_keyword);
hostsCounter++;
}
else if (domainRule.domain_suffix?.Count > 0)
{
hostsResolveRule.domain_suffix ??= [];
hostsResolveRule.domain_suffix.AddRange(domainRule.domain_suffix);
hostsCounter++;
}
else if (domainRule.domain_regex?.Count > 0)
{
hostsResolveRule.domain_regex ??= [];
hostsResolveRule.domain_regex.AddRange(domainRule.domain_regex);
hostsCounter++;
}
else if (domainRule.geosite?.Count > 0)
{
hostsResolveRule.geosite ??= [];
hostsResolveRule.geosite.AddRange(domainRule.geosite);
hostsCounter++;
}
}
if (hostsCounter > 0)
{
_coreConfig.route.rules.Add(hostsResolveRule);
}
}
_coreConfig.route.rules.Add(new()
@@ -355,6 +402,11 @@ public partial class CoreConfigSingboxService
rule.domain_keyword ??= [];
rule.domain_keyword?.Add(domain.Substring(8));
}
else if (domain.StartsWith("dotless:"))
{
rule.domain_keyword ??= [];
rule.domain_keyword?.Add(domain.Substring(8));
}
else
{
rule.domain_keyword ??= [];

View File

@@ -301,6 +301,7 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
GenLog();
_coreConfig.outbounds.Clear();
GenOutbounds();
GenStatistic();
var protectNode = new ProfileItem()
{
@@ -326,18 +327,17 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
Node = protectNode,
}).BuildProxyOutbound("tun-project-ss"));
_coreConfig.routing.rules ??= [];
var hasBalancer = _coreConfig.routing.balancers is { Count: > 0 };
_coreConfig.routing.rules =
[
new()
{
inboundTag = new List<string> { "proxy-relay-ss" },
outboundTag = hasBalancer ? null : Global.ProxyTag,
balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix: null,
type = "field"
}
];
_coreConfig.inbounds.Clear();
_coreConfig.routing.rules.Add(new()
{
inboundTag = ["proxy-relay-ss"],
outboundTag = hasBalancer ? null : Global.ProxyTag,
balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix : null,
type = "field"
});
//_coreConfig.inbounds.Clear();
var configNode = JsonUtils.ParseJson(JsonUtils.Serialize(_coreConfig))!;
configNode["inbounds"]!.AsArray().Add(new

View File

@@ -437,7 +437,7 @@ public partial class CoreConfigV2rayService
FillDnsDomainsCustom(obj);
_coreConfig.dns = JsonUtils.Deserialize<Dns4Ray>(JsonUtils.Serialize(obj));
_coreConfig.dns = obj;
}
catch (Exception ex)
{

View File

@@ -34,8 +34,8 @@ public partial class DNSSettingWindow
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);