Add process name (Tun mode) to the rule

Add Tun DNS in the DNS settings of sing-box
Remove Tun mode settings process name and dns
This commit is contained in:
2dust 2023-05-07 19:09:13 +08:00
parent 94cc36a08f
commit 032d12a592
18 changed files with 139 additions and 616 deletions

View file

@ -132,7 +132,6 @@ namespace v2rayN.Handler
config.tunModeItem = new TunModeItem config.tunModeItem = new TunModeItem
{ {
enableTun = false, enableTun = false,
showWindow = true,
mtu = 9000, mtu = 9000,
}; };
} }

View file

@ -452,38 +452,6 @@ namespace v2rayN.Handler
} }
} }
} }
if (_config.tunModeItem.enableTun)
{
if (_config.tunModeItem.bypassMode)
{
//direct ips
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0)
{
singboxConfig.route.rules.Add(new() { outbound = "direct", ip_cidr = _config.tunModeItem.directIP });
}
//direct process
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
{
singboxConfig.route.rules.Add(new() { outbound = "direct", process_name = _config.tunModeItem.directProcess });
}
}
else
{
//proxy ips
if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0)
{
singboxConfig.route.rules.Add(new() { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP });
}
//proxy process
if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0)
{
singboxConfig.route.rules.Add(new() { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess });
}
singboxConfig.route.rules.Add(new() { outbound = "direct", inbound = new() { "tun-in" } });
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -552,6 +520,7 @@ namespace v2rayN.Handler
rule.inbound = item.inboundTag; rule.inbound = item.inboundTag;
} }
var rule2 = Utils.DeepCopy(rule); var rule2 = Utils.DeepCopy(rule);
var rule3 = Utils.DeepCopy(rule);
var hasDomainIp = false; var hasDomainIp = false;
if (item.domain?.Count > 0) if (item.domain?.Count > 0)
@ -574,6 +543,13 @@ namespace v2rayN.Handler
hasDomainIp = true; hasDomainIp = true;
} }
if (_config.tunModeItem.enableTun && item.process?.Count > 0)
{
rule3.process_name = item.process;
rules.Add(rule3);
hasDomainIp = true;
}
if (!hasDomainIp) if (!hasDomainIp)
{ {
rules.Add(rule); rules.Add(rule);
@ -659,16 +635,9 @@ namespace v2rayN.Handler
Dns4Sbox? dns4Sbox; Dns4Sbox? dns4Sbox;
if (_config.tunModeItem.enableTun) if (_config.tunModeItem.enableTun)
{ {
string tunDNS = String.Empty; var item = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
if (_config.tunModeItem.bypassMode) var tunDNS = item?.tunDNS;
{ if (string.IsNullOrWhiteSpace(tunDNS))
tunDNS = _config.tunModeItem.directDNS;
}
else
{
tunDNS = _config.tunModeItem.proxyDNS;
}
if (tunDNS.IsNullOrEmpty() || Utils.FromJson<Dns4Sbox>(tunDNS) is null)
{ {
tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName); tunDNS = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
} }

View file

@ -1,361 +0,0 @@
using System.Diagnostics;
using System.IO;
using System.Reactive.Linq;
using v2rayN.Handler;
using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Base
{
public sealed class TunHandler
{
private static readonly Lazy<TunHandler> _instance = new(() => new());
public static TunHandler Instance => _instance.Value;
private string _tunConfigName = "tunConfig.json";
private static Config _config;
private CoreInfo coreInfo;
private Process? _process;
private static int _socksPort;
private static bool _needRestart = true;
private static bool _isRunning = false;
public TunHandler()
{
_config = LazyConfig.Instance.GetConfig();
Observable.Interval(TimeSpan.FromSeconds(10))
.Subscribe(x =>
{
if (_isRunning && _config.tunModeItem.enableTun)
{
if (_process == null || _process.HasExited)
{
if (Init() == false)
{
return;
}
CoreStart();
Utils.SaveLog("Tun mode monitors restart");
}
}
});
}
public void Start()
{
var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
if (socksPort == _socksPort
&& _process != null
&& !_process.HasExited)
{
_needRestart = false;
}
_socksPort = socksPort;
if (_needRestart)
{
CoreStop();
if (Init() == false)
{
return;
}
CoreStartTest();
CoreStart();
}
}
public void Stop()
{
CoreStop();
}
private bool Init()
{
coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box);
//Template
string configStr = Utils.GetEmbedText(Global.TunSingboxFileName);
if (!Utils.IsNullOrEmpty(_config.tunModeItem.customTemplate) && File.Exists(_config.tunModeItem.customTemplate))
{
var customTemplate = File.ReadAllText(_config.tunModeItem.customTemplate);
if (!Utils.IsNullOrEmpty(customTemplate))
{
configStr = customTemplate;
}
}
if (Utils.IsNullOrEmpty(configStr))
{
return false;
}
//settings
if (_config.tunModeItem.mtu <= 0)
{
_config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]);
}
if (Utils.IsNullOrEmpty(_config.tunModeItem.stack))
{
_config.tunModeItem.stack = Global.TunStacks[0];
}
configStr = configStr.Replace("$mtu$", $"{_config.tunModeItem.mtu}");
configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}");
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}");
//logs
configStr = configStr.Replace("$log_disabled$", $"{(!_config.tunModeItem.enabledLog).ToString().ToLower()}");
if (_config.tunModeItem.showWindow)
{
configStr = configStr.Replace("$log_output$", $"");
}
else
{
var dtNow = DateTime.Now;
var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow:yyyy-MM-dd}.txt")}\", ";
configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}");
}
//port
configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
//dns
string dnsObject = String.Empty;
if (_config.tunModeItem.bypassMode)
{
dnsObject = _config.tunModeItem.directDNS;
}
else
{
dnsObject = _config.tunModeItem.proxyDNS;
}
if (dnsObject.IsNullOrEmpty() || Utils.ParseJson(dnsObject)?.ContainsKey("servers") == false)
{
dnsObject = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
}
configStr = configStr.Replace("$dns_object$", dnsObject);
//exe
routingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe);
string strDns = string.Join("\",\"", lstDnsExe.ToArray());
configStr = configStr.Replace("$dnsProcessName$", $"\"{strDns}\"");
string strDirect = string.Join("\",\"", lstDirectExe.ToArray());
configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\"");
if (_config.tunModeItem.bypassMode)
{
//direct ips
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0)
{
var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP };
configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips));
}
//direct process
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
{
var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess };
configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process));
}
}
else
{
//proxy ips
if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0)
{
var ips = new { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP };
configStr = configStr.Replace("$ruleProxyIPs$", "," + Utils.ToJson(ips));
}
//proxy process
if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0)
{
var process = new { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess };
configStr = configStr.Replace("$ruleProxyProcess$", "," + Utils.ToJson(process));
}
var final = new { outbound = "direct", inbound = "tun-in" };
configStr = configStr.Replace("$ruleFinally$", "," + Utils.ToJson(final));
}
configStr = configStr.Replace("$ruleDirectIPs$", "");
configStr = configStr.Replace("$ruleDirectProcess$", "");
configStr = configStr.Replace("$ruleProxyIPs$", "");
configStr = configStr.Replace("$ruleProxyProcess$", "");
configStr = configStr.Replace("$ruleFinally$", "");
File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr);
return true;
}
private void routingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe)
{
lstDnsExe = new();
lstDirectExe = new();
var coreInfos = LazyConfig.Instance.GetCoreInfos();
foreach (var it in coreInfos)
{
if (it.coreType == ECoreType.v2rayN)
{
continue;
}
foreach (var it2 in it.coreExes)
{
if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
{
lstDnsExe.Add($"{it2}.exe");
}
if (!lstDirectExe.Contains(it2))
{
lstDirectExe.Add($"{it2}.exe");
}
}
}
}
private void CoreStop()
{
try
{
_isRunning = false;
if (_process != null)
{
KillProcess(_process);
_process.Dispose();
_process = null;
_needRestart = true;
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
}
}
private string CoreFindexe()
{
string fileName = string.Empty;
foreach (string name in coreInfo.coreExes)
{
string vName = $"{name}.exe";
vName = Utils.GetBinPath(vName, coreInfo.coreType);
if (File.Exists(vName))
{
fileName = vName;
break;
}
}
if (Utils.IsNullOrEmpty(fileName))
{
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
Utils.SaveLog(msg);
}
return fileName;
}
private void CoreStart()
{
try
{
string fileName = CoreFindexe();
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
var showWindow = _config.tunModeItem.showWindow;
Process p = new()
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = showWindow,
CreateNoWindow = !showWindow,
//RedirectStandardError = !showWindow,
Verb = "runas",
}
};
p.Start();
_process = p;
_isRunning = true;
if (p.WaitForExit(1000))
{
//if (showWindow)
//{
throw new Exception("start tun mode fail");
//}
//else
//{
// throw new Exception(p.StandardError.ReadToEnd());
//}
}
Global.processJob.AddProcess(p.Handle);
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
}
}
private void KillProcess(Process p)
{
try
{
p.CloseMainWindow();
p.WaitForExit(100);
if (!p.HasExited)
{
p.Kill();
p.WaitForExit(100);
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
}
}
private int CoreStartTest()
{
Utils.SaveLog("Tun mode configuration file test start");
try
{
string fileName = CoreFindexe();
if (fileName == "")
{
return -1;
}
Process p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
Verb = "runas",
}
};
p.Start();
if (p.WaitForExit(2000))
{
throw new Exception(p.StandardError.ReadToEnd());
}
KillProcess(p);
return 0;
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
return -1;
}
finally
{
Utils.SaveLog("Tun mode configuration file test end");
}
}
}
}

View file

@ -161,19 +161,9 @@ namespace v2rayN.Mode
public class TunModeItem public class TunModeItem
{ {
public bool enableTun { get; set; } public bool enableTun { get; set; }
public bool showWindow { get; set; }
public bool enabledLog { get; set; }
public bool strictRoute { get; set; } public bool strictRoute { get; set; }
public string stack { get; set; } public string stack { get; set; }
public int mtu { get; set; } public int mtu { get; set; }
public string customTemplate { get; set; }
public bool bypassMode { get; set; } = true;
public List<string> directIP { get; set; }
public List<string> directProcess { get; set; }
public string directDNS { get; set; }
public List<string> proxyIP { get; set; }
public List<string> proxyProcess { get; set; }
public string proxyDNS { get; set; }
} }
[Serializable] [Serializable]

View file

@ -12,8 +12,7 @@ namespace v2rayN.Mode
public bool enabled { get; set; } = true; public bool enabled { get; set; } = true;
public ECoreType coreType { get; set; } public ECoreType coreType { get; set; }
public string? normalDNS { get; set; } public string? normalDNS { get; set; }
public string? directDNS { get; set; } public string? tunDNS { get; set; }
public string? proxyDNS { get; set; }
public string? domainStrategy4Freedom { get; set; } public string? domainStrategy4Freedom { get; set; }
} }
} }

View file

@ -18,6 +18,8 @@
public List<string> protocol { get; set; } public List<string> protocol { get; set; }
public List<string> process { get; set; }
public bool enabled { get; set; } = true; public bool enabled { get; set; } = true;
} }
} }

View file

@ -1853,7 +1853,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Domain and ip are auto sorted when saving 的本地化字符串。 /// 查找类似 Domain, ip, process are auto sorted when saving 的本地化字符串。
/// </summary> /// </summary>
public static string TbAutoSort { public static string TbAutoSort {
get { get {
@ -2167,6 +2167,33 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Domain 的本地化字符串。
/// </summary>
public static string TbRoutingRuleDomain {
get {
return ResourceManager.GetString("TbRoutingRuleDomain", resourceCulture);
}
}
/// <summary>
/// 查找类似 IP or IP CIDR 的本地化字符串。
/// </summary>
public static string TbRoutingRuleIP {
get {
return ResourceManager.GetString("TbRoutingRuleIP", resourceCulture);
}
}
/// <summary>
/// 查找类似 Full process name (Tun mode) 的本地化字符串。
/// </summary>
public static string TbRoutingRuleProcess {
get {
return ResourceManager.GetString("TbRoutingRuleProcess", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 3.Block Domain or IP 的本地化字符串。 /// 查找类似 3.Block Domain or IP 的本地化字符串。
/// </summary> /// </summary>
@ -2779,15 +2806,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable: If no route matches, the final proxy 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeBypassModeTip {
get {
return ResourceManager.GetString("TbSettingsTunModeBypassModeTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Custom Template 的本地化字符串。 /// 查找类似 Custom Template 的本地化字符串。
/// </summary> /// </summary>

View file

@ -941,7 +941,7 @@
<value>RoutingRuleDetailsSetting</value> <value>RoutingRuleDetailsSetting</value>
</data> </data>
<data name="TbAutoSort" xml:space="preserve"> <data name="TbAutoSort" xml:space="preserve">
<value>Domain and ip are auto sorted when saving</value> <value>Domain, ip, process are auto sorted when saving</value>
</data> </data>
<data name="TbRuleobjectDoc" xml:space="preserve"> <data name="TbRuleobjectDoc" xml:space="preserve">
<value>Ruleobject Doc</value> <value>Ruleobject Doc</value>
@ -1057,9 +1057,6 @@
<data name="TbSettingsTunModeBypassMode" xml:space="preserve"> <data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>Bypass Mode</value> <value>Bypass Mode</value>
</data> </data>
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
<value>Enable: If no route matches, the final proxy</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve"> <data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value> <value>SpeedTest Single Timeout Value</value>
</data> </data>
@ -1132,4 +1129,13 @@
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve"> <data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value> <value>sing-box Mux Protocol</value>
</data> </data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
</root> </root>

View file

@ -941,7 +941,7 @@
<value>路由规则详情设置</value> <value>路由规则详情设置</value>
</data> </data>
<data name="TbAutoSort" xml:space="preserve"> <data name="TbAutoSort" xml:space="preserve">
<value>保存时Domain和IP自动排序</value> <value>保存时Domain, IP, 进程名 自动排序</value>
</data> </data>
<data name="TbRuleobjectDoc" xml:space="preserve"> <data name="TbRuleobjectDoc" xml:space="preserve">
<value>规则详细说明文档</value> <value>规则详细说明文档</value>
@ -1057,9 +1057,6 @@
<data name="TbSettingsTunModeBypassMode" xml:space="preserve"> <data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>绕行模式</value> <value>绕行模式</value>
</data> </data>
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
<value>启用:路由无匹配则最终代理</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve"> <data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>测速单个超时值</value> <value>测速单个超时值</value>
</data> </data>
@ -1129,4 +1126,13 @@
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve"> <data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux 多路复用协议</value> <value>sing-box Mux 多路复用协议</value>
</data> </data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>进程名全称 (Tun模式)</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP 或 IP CIDR</value>
</data>
</root> </root>

View file

@ -18,6 +18,8 @@ namespace v2rayN.ViewModels
[Reactive] public string domainStrategy4Freedom { get; set; } [Reactive] public string domainStrategy4Freedom { get; set; }
[Reactive] public string normalDNS { get; set; } [Reactive] public string normalDNS { get; set; }
[Reactive] public string normalDNS2 { get; set; } [Reactive] public string normalDNS2 { get; set; }
[Reactive] public string tunDNS2 { get; set; }
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; } public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
@ -35,6 +37,7 @@ namespace v2rayN.ViewModels
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box); var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
normalDNS2 = item2?.normalDNS!; normalDNS2 = item2?.normalDNS!;
tunDNS2 = item2?.tunDNS!;
SaveCmd = ReactiveCommand.Create(() => SaveCmd = ReactiveCommand.Create(() =>
{ {
@ -49,6 +52,7 @@ namespace v2rayN.ViewModels
ImportDefConfig4SingboxCmd = ReactiveCommand.Create(() => ImportDefConfig4SingboxCmd = ReactiveCommand.Create(() =>
{ {
normalDNS2 = Utils.GetEmbedText(Global.DNSSingboxNormalFileName); normalDNS2 = Utils.GetEmbedText(Global.DNSSingboxNormalFileName);
tunDNS2 = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
}); });
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
@ -80,6 +84,15 @@ namespace v2rayN.ViewModels
return; return;
} }
} }
if (!Utils.IsNullOrEmpty(tunDNS2))
{
var obj2 = Utils.FromJson<Dns4Sbox>(tunDNS2);
if (obj2 == null)
{
UI.Show(ResUI.FillCorrectDNSText);
return;
}
}
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray); var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
item.domainStrategy4Freedom = domainStrategy4Freedom; item.domainStrategy4Freedom = domainStrategy4Freedom;
@ -88,6 +101,7 @@ namespace v2rayN.ViewModels
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box); var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
item2.normalDNS = Utils.ToJson(Utils.ParseJson(normalDNS2)); item2.normalDNS = Utils.ToJson(Utils.ParseJson(normalDNS2));
item2.tunDNS = Utils.ToJson(Utils.ParseJson(tunDNS2));
ConfigHandler.SaveDNSItems(_config, item2); ConfigHandler.SaveDNSItems(_config, item2);
_noticeHandler?.Enqueue(ResUI.OperationSuccess); _noticeHandler?.Enqueue(ResUI.OperationSuccess);

View file

@ -79,20 +79,9 @@ namespace v2rayN.ViewModels
#region Tun mode #region Tun mode
[Reactive] public bool TunShowWindow { get; set; }
[Reactive] public bool TunEnabledLog { get; set; }
[Reactive] public bool TunStrictRoute { get; set; } [Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; } [Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public string TunCustomTemplate { get; set; }
[Reactive] public bool TunBypassMode { get; set; }
[Reactive] public bool TunBypassMode2 { get; set; }
[Reactive] public string TunDirectIP { get; set; }
[Reactive] public string TunDirectProcess { get; set; }
[Reactive] public string TunDirectDNS { get; set; }
[Reactive] public string TunProxyIP { get; set; }
[Reactive] public string TunProxyProcess { get; set; }
[Reactive] public string TunProxyDNS { get; set; }
#endregion Tun mode #endregion Tun mode
@ -180,22 +169,9 @@ namespace v2rayN.ViewModels
#region Tun mode #region Tun mode
TunShowWindow = _config.tunModeItem.showWindow;
TunEnabledLog = _config.tunModeItem.enabledLog;
TunStrictRoute = _config.tunModeItem.strictRoute; TunStrictRoute = _config.tunModeItem.strictRoute;
TunStack = _config.tunModeItem.stack; TunStack = _config.tunModeItem.stack;
TunMtu = _config.tunModeItem.mtu; TunMtu = _config.tunModeItem.mtu;
TunCustomTemplate = _config.tunModeItem.customTemplate;
TunBypassMode = _config.tunModeItem.bypassMode;
TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true);
TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true);
TunDirectDNS = _config.tunModeItem.directDNS;
TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true);
TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true);
TunProxyDNS = _config.tunModeItem.proxyDNS;
this.WhenAnyValue(
x => x.TunBypassMode)
.Subscribe(c => TunBypassMode2 = !TunBypassMode);
#endregion Tun mode #endregion Tun mode
@ -341,19 +317,9 @@ namespace v2rayN.ViewModels
_config.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol; _config.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
//tun mode //tun mode
_config.tunModeItem.showWindow = TunShowWindow;
_config.tunModeItem.enabledLog = TunEnabledLog;
_config.tunModeItem.strictRoute = TunStrictRoute; _config.tunModeItem.strictRoute = TunStrictRoute;
_config.tunModeItem.stack = TunStack; _config.tunModeItem.stack = TunStack;
_config.tunModeItem.mtu = TunMtu; _config.tunModeItem.mtu = TunMtu;
_config.tunModeItem.customTemplate = TunCustomTemplate;
_config.tunModeItem.bypassMode = TunBypassMode;
_config.tunModeItem.directIP = Utils.String2List(Utils.Convert2Comma(TunDirectIP));
_config.tunModeItem.directProcess = Utils.String2List(Utils.Convert2Comma(TunDirectProcess));
_config.tunModeItem.directDNS = Utils.ToJson(Utils.ParseJson(TunDirectDNS));
_config.tunModeItem.proxyIP = Utils.String2List(Utils.Convert2Comma(TunProxyIP));
_config.tunModeItem.proxyProcess = Utils.String2List(Utils.Convert2Comma(TunProxyProcess));
_config.tunModeItem.proxyDNS = Utils.ToJson(Utils.ParseJson(TunProxyDNS));
//coreType //coreType
SaveCoreType(); SaveCoreType();

View file

@ -27,6 +27,8 @@ namespace v2rayN.ViewModels
[Reactive] [Reactive]
public string IP { get; set; } public string IP { get; set; }
[Reactive]
public string Process { get; set; }
[Reactive] [Reactive]
public bool AutoSort { get; set; } public bool AutoSort { get; set; }
@ -53,6 +55,7 @@ namespace v2rayN.ViewModels
Domain = Utils.List2String(SelectedSource.domain, true); Domain = Utils.List2String(SelectedSource.domain, true);
IP = Utils.List2String(SelectedSource.ip, true); IP = Utils.List2String(SelectedSource.ip, true);
Process = Utils.List2String(SelectedSource.process, true);
SaveCmd = ReactiveCommand.Create(() => SaveCmd = ReactiveCommand.Create(() =>
{ {
@ -66,16 +69,19 @@ namespace v2rayN.ViewModels
{ {
Domain = Utils.Convert2Comma(Domain); Domain = Utils.Convert2Comma(Domain);
IP = Utils.Convert2Comma(IP); IP = Utils.Convert2Comma(IP);
Process = Utils.Convert2Comma(Process);
if (AutoSort) if (AutoSort)
{ {
SelectedSource.domain = Utils.String2ListSorted(Domain); SelectedSource.domain = Utils.String2ListSorted(Domain);
SelectedSource.ip = Utils.String2ListSorted(IP); SelectedSource.ip = Utils.String2ListSorted(IP);
SelectedSource.process = Utils.String2ListSorted(Process);
} }
else else
{ {
SelectedSource.domain = Utils.String2List(Domain); SelectedSource.domain = Utils.String2List(Domain);
SelectedSource.ip = Utils.String2List(IP); SelectedSource.ip = Utils.String2List(IP);
SelectedSource.process = Utils.String2List(Process);
} }
SelectedSource.protocol = ProtocolItems?.ToList(); SelectedSource.protocol = ProtocolItems?.ToList();
SelectedSource.inboundTag = InboundTagItems?.ToList(); SelectedSource.inboundTag = InboundTagItems?.ToList();

View file

@ -4,7 +4,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters" xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:v2rayN.Resx" xmlns:resx="clr-namespace:v2rayN.Resx"
@ -115,15 +114,44 @@
Cursor="Hand" Cursor="Hand"
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
</StackPanel> </StackPanel>
<TextBox
x:Name="txtnormalDNS2" <Grid Margin="{StaticResource SettingItemMargin}">
Margin="{StaticResource SettingItemMargin}" <Grid.ColumnDefinitions>
VerticalAlignment="Stretch" <ColumnDefinition Width="1*" />
AcceptsReturn="True" <ColumnDefinition Width="10" />
BorderThickness="1" <ColumnDefinition Width="1*" />
Style="{StaticResource DefTextBox}" </Grid.ColumnDefinitions>
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> <GroupBox
Grid.Column="0"
Header=""
Style="{StaticResource MyGroupBox}">
<TextBox
x:Name="txtnormalDNS2"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Stretch"
AcceptsReturn="True"
BorderThickness="1"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="{x:Static resx:ResUI.TbSettingsTunMode}"
Style="{StaticResource MyGroupBox}">
<TextBox
x:Name="txttunDNS2"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Stretch"
AcceptsReturn="True"
BorderThickness="1"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid>
</DockPanel> </DockPanel>
</TabItem> </TabItem>
</TabControl> </TabControl>

View file

@ -29,6 +29,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.normalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.normalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.normalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.normalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.tunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);

View file

@ -792,13 +792,6 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@ -851,125 +844,6 @@
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsTunModeBypassMode}" />
<ToggleButton
x:Name="togBypassMode"
Grid.Row="6"
Grid.Column="1"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Column="2"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsTunModeBypassModeTip}" />
</Grid>
<Grid
x:Name="gridTunModeDirect"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectIP}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectIP"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectProcess}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectProcess"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbSettingsTunModeDNS}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectDNS"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid>
<Grid
x:Name="gridTunModeProxy"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
Header="{x:Static resx:ResUI.TbSettingsTunModeProxyIP}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyIP"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="{x:Static resx:ResUI.TbSettingsTunModeProxyProcess}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyProcess"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbSettingsTunModeDNS}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyDNS"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid> </Grid>
</DockPanel> </DockPanel>
</TabItem> </TabItem>

View file

@ -173,15 +173,6 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunBypassMode, v => v.togBypassMode.IsChecked).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.TunBypassMode, v => v.gridTunModeDirect.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.TunBypassMode2, v => v.gridTunModeProxy.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectDNS, v => v.txtDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyIP, v => v.txtProxyIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyProcess, v => v.txtProxyProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyDNS, v => v.txtProxyDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables);

View file

@ -172,10 +172,12 @@
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" /> <ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="Domain" Header="{x:Static resx:ResUI.TbRoutingRuleDomain}"
Style="{StaticResource MyGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDomain" Name="txtDomain"
@ -187,7 +189,7 @@
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="IP" Header="{x:Static resx:ResUI.TbRoutingRuleIP}"
Style="{StaticResource MyGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtIP" Name="txtIP"
@ -196,6 +198,18 @@
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbRoutingRuleProcess}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProcess"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid> </Grid>
</DockPanel> </DockPanel>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View file

@ -49,6 +49,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedSource.enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Domain, v => v.txtDomain.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Domain, v => v.txtDomain.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.IP, v => v.txtIP.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.IP, v => v.txtIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Process, v => v.txtProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoSort, v => v.chkAutoSort.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoSort, v => v.chkAutoSort.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);