diff --git a/Netch/Constants.cs b/Netch/Constants.cs index 716639ad..5ec78658 100644 --- a/Netch/Constants.cs +++ b/Netch/Constants.cs @@ -23,5 +23,9 @@ } public const string WintunDllFile = "bin\\wintun.dll"; + public const string DisableModeDirectoryFileName = "disabled"; + + public const string DefaultPrimaryDNS = "1.1.1.1:53"; + public const string DefaultCNPrimaryDNS = "223.5.5.5:53"; } } \ No newline at end of file diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 6fe193bd..783194b9 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -4,10 +4,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.Threading; -using Netch.Enums; using Netch.Interfaces; using Netch.Models; +using Netch.Models.Modes; using Netch.Servers; +using Netch.Services; using Netch.Utils; using Serilog; @@ -25,8 +26,6 @@ namespace Netch.Controllers public static IModeController? ModeController { get; private set; } - public static ModeFeature ModeFeatures { get; private set; } - private static readonly AsyncSemaphore Lock = new(1); public static async Task StartAsync(Server server, Mode mode) @@ -49,12 +48,12 @@ namespace Netch.Controllers try { - (ModeController, ModeFeatures) = ModeHelper.GetModeControllerByType(mode.Type, out var modePort, out var portName); + ModeController = ModeService.GetModeControllerByType(mode.Type, out var modePort, out var portName); if (modePort != null) TryReleaseTcpPort((ushort)modePort, portName); - if (Server is Socks5Server socks5 && (!socks5.Auth() || ModeFeatures.HasFlag(ModeFeature.SupportSocks5Auth))) + if (Server is Socks5Server socks5 && (!socks5.Auth() || ModeController.Features.HasFlag(ModeFeature.SupportSocks5Auth))) { Socks5Server = socks5; } @@ -75,6 +74,7 @@ namespace Netch.Controllers // Start Mode Controller Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name)); + await ModeController.StartAsync(Socks5Server, mode); } catch (Exception e) @@ -130,7 +130,6 @@ namespace Netch.Controllers ServerController = null; ModeController = null; - ModeFeatures = 0; } public static void PortCheck(ushort port, string portName, PortType portType = PortType.Both) diff --git a/Netch/Controllers/NFController.cs b/Netch/Controllers/NFController.cs index 9c2ecf80..c761d0b6 100644 --- a/Netch/Controllers/NFController.cs +++ b/Netch/Controllers/NFController.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; using System.ServiceProcess; using System.Threading.Tasks; using Netch.Interfaces; -using Netch.Interops; using Netch.Models; +using Netch.Models.Modes; +using Netch.Models.Modes.ProcessMode; using Netch.Servers; using Netch.Utils; using Serilog; @@ -17,7 +19,7 @@ namespace Netch.Controllers public class NFController : IModeController { private Server? _server; - private Mode? _mode; + private Redirector _mode = null!; private RedirectorConfig _rdrConfig = null!; private static readonly ServiceController NFService = new("netfilter2"); @@ -26,41 +28,55 @@ namespace Netch.Controllers public string Name => "Redirector"; + public ModeFeature Features => ModeFeature.SupportIPv6 | ModeFeature.SupportSocks5Auth; + public async Task StartAsync(Socks5Server server, Mode mode) { + if (mode is not Redirector processMode) + throw new InvalidOperationException(); + _server = server; - _mode = mode; + _mode = processMode; _rdrConfig = Global.Settings.Redirector; + CheckDriver(); - Dial(NameList.AIO_FILTERLOOPBACK, "false"); - Dial(NameList.AIO_FILTERINTRANET, "true"); - Dial(NameList.AIO_FILTERPARENT, _rdrConfig.ChildProcessHandle.ToString().ToLower()); - Dial(NameList.AIO_FILTERICMP, _rdrConfig.FilterICMP.ToString().ToLower()); - Dial(NameList.AIO_ICMPING, _rdrConfig.ICMPDelay.ToString()); + Dial(NameList.AIO_FILTERLOOPBACK, _mode.FilterLoopback); + Dial(NameList.AIO_FILTERINTRANET, _mode.FilterIntranet); + Dial(NameList.AIO_FILTERPARENT, _mode.FilterParent ?? _rdrConfig.HandleOnlyDNS); + Dial(NameList.AIO_FILTERICMP, _mode.FilterICMP ?? _rdrConfig.FilterICMP); + if (_mode.FilterICMP ?? _rdrConfig.FilterICMP) + Dial(NameList.AIO_ICMPING, (_mode.FilterICMP != null ? _mode.ICMPDelay ?? 10 : _rdrConfig.ICMPDelay).ToString()); + + Dial(NameList.AIO_FILTERTCP, _mode.FilterTCP ?? _rdrConfig.FilterTCP); + Dial(NameList.AIO_FILTERUDP, _mode.FilterUDP ?? _rdrConfig.FilterUDP); + + // DNS + Dial(NameList.AIO_FILTERDNS, _mode.FilterDNS ?? _rdrConfig.FilterDNS); + Dial(NameList.AIO_DNSONLY, _mode.HandleOnlyDNS ?? _rdrConfig.HandleOnlyDNS); + Dial(NameList.AIO_DNSPROX, _mode.DNSProxy ?? _rdrConfig.DNSProxy); + if (_mode.FilterDNS ?? _rdrConfig.FilterDNS) + { + var dnsStr = _mode.FilterDNS != null ? _mode.DNSHost : _rdrConfig.DNSHost; + + dnsStr = dnsStr.ValueOrDefault() ?? Constants.DefaultPrimaryDNS; + + var dns = IPEndPoint.Parse(dnsStr); + if (dns.Port == 0) + dns.Port = 53; + + Dial(NameList.AIO_DNSHOST, dns.Address.ToString()); + Dial(NameList.AIO_DNSPORT, dns.Port.ToString()); + } // Server - Dial(NameList.AIO_FILTERUDP, _rdrConfig.FilterProtocol.HasFlag(PortType.UDP).ToString().ToLower()); - Dial(NameList.AIO_FILTERTCP, _rdrConfig.FilterProtocol.HasFlag(PortType.TCP).ToString().ToLower()); - Dial(NameList.AIO_TGTHOST, await server.AutoResolveHostnameAsync()); Dial(NameList.AIO_TGTPORT, server.Port.ToString()); Dial(NameList.AIO_TGTUSER, server.Username ?? string.Empty); Dial(NameList.AIO_TGTPASS, server.Password ?? string.Empty); // Mode Rule - DialRule(_mode); - - // DNS - Dial(NameList.AIO_FILTERDNS, _rdrConfig.DNSHijack.ToString().ToLower()); - Dial(NameList.AIO_DNSONLY, "false"); - Dial(NameList.AIO_DNSPROX, "true"); - if (_rdrConfig.DNSHijack) - { - var dns = new Uri(DnsUtils.AppendScheme(DnsUtils.AppendPort(_rdrConfig.DNSHijackHost), "udp")); - Dial(NameList.AIO_DNSHOST, dns.Host); - Dial(NameList.AIO_DNSPORT, dns.Port.ToString()); - } + DialRule(); if (!await InitAsync()) throw new MessageException("Redirector start failed."); @@ -113,20 +129,18 @@ namespace Netch.Controllers #endregion - private void DialRule(Mode mode) + private void DialRule() { Dial(NameList.AIO_CLRNAME, ""); var invalidList = new List(); - foreach (var s in mode.GetRules()) + foreach (var s in _mode.Bypass) { - if (s.StartsWith("!")) - { - if (!Dial(NameList.AIO_BYPNAME, s.Substring(1))) - invalidList.Add(s); - - continue; - } + if (!Dial(NameList.AIO_BYPNAME, s)) + invalidList.Add(s); + } + foreach (var s in _mode.Handle) + { if (!Dial(NameList.AIO_ADDNAME, s)) invalidList.Add(s); } @@ -204,7 +218,7 @@ namespace Netch.Controllers } // 注册驱动文件 - if (Redirector.aio_register("netfilter2")) + if (Interops.Redirector.aio_register("netfilter2")) { Log.Information("Install netfilter2 driver finished"); } @@ -237,7 +251,7 @@ namespace Netch.Controllers if (!File.Exists(SystemDriver)) return true; - Redirector.aio_unregister("netfilter2"); + Interops.Redirector.aio_unregister("netfilter2"); File.Delete(SystemDriver); return true; diff --git a/Netch/Controllers/PcapController.cs b/Netch/Controllers/PcapController.cs index 5063b642..c610db12 100644 --- a/Netch/Controllers/PcapController.cs +++ b/Netch/Controllers/PcapController.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -10,6 +8,8 @@ using Microsoft.VisualStudio.Threading; using Netch.Forms; using Netch.Interfaces; using Netch.Models; +using Netch.Models.Modes; +using Netch.Models.Modes.ShareMode; using Netch.Servers; using Netch.Utils; @@ -18,8 +18,8 @@ namespace Netch.Controllers public class PcapController : Guard, IModeController { private readonly LogForm _form; - private Mode? _mode; - private Server? _server; + private ShareMode _mode = null!; + private Socks5Server _server = null!; public PcapController() : base("pcap2socks.exe", encoding: Encoding.UTF8) { @@ -31,20 +31,25 @@ namespace Netch.Controllers public override string Name => "pcap2socks"; + public ModeFeature Features => 0; + public async Task StartAsync(Socks5Server server, Mode mode) { + if (mode is not ShareMode shareMode) + throw new InvalidOperationException(); + _server = server; - _mode = mode; + _mode = shareMode; var outboundNetworkInterface = NetworkInterfaceUtils.GetBest(); var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.Id}"); - if (_server is Socks5Server socks5 && !socks5.Auth()) - argument.Append($" --destination {await socks5.AutoResolveHostnameAsync()}:{socks5.Port}"); + if (!_server.Auth()) + argument.Append($" --destination {await _server.AutoResolveHostnameAsync()}:{_server.Port}"); else - Trace.Assert(false); + throw new InvalidOperationException(); - argument.Append($" {_mode.GetRules().FirstOrDefault() ?? "-P n"}"); + argument.Append($" {_mode.Argument}"); await StartGuardAsync(argument.ToString()); } diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index 505f5801..450b678a 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -1,13 +1,13 @@ using System; -using System.Diagnostics; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; -using Netch.Enums; using Netch.Interfaces; using Netch.Interops; using Netch.Models; +using Netch.Models.Modes; +using Netch.Models.Modes.TunMode; using Netch.Servers; using Netch.Utils; using Serilog; @@ -21,7 +21,7 @@ namespace Netch.Controllers private readonly DNSController _aioDnsController = new(); - private Mode _mode = null!; + private TunMode _mode = null!; private IPAddress? _serverRemoteAddress; private TUNConfig _tunConfig = null!; @@ -30,9 +30,14 @@ namespace Netch.Controllers public string Name => "tun2socks"; + public ModeFeature Features => ModeFeature.SupportSocks5Auth; + public async Task StartAsync(Socks5Server server, Mode mode) { - _mode = mode; + if (mode is not TunMode tunMode) + throw new InvalidOperationException(); + + _mode = tunMode; _tunConfig = Global.Settings.TUNTAP; if (server is Socks5LocalServer socks5Bridge) @@ -58,24 +63,17 @@ namespace Netch.Controllers Dial(NameList.TYPE_UDPREST, ""); Dial(NameList.TYPE_UDPTYPE, "Socks5"); - if (server is Socks5Server socks5) + Dial(NameList.TYPE_TCPHOST, $"{await server.AutoResolveHostnameAsync()}:{server.Port}"); + + Dial(NameList.TYPE_UDPHOST, $"{await server.AutoResolveHostnameAsync()}:{server.Port}"); + + if (server.Auth()) { - Dial(NameList.TYPE_TCPHOST, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}"); + Dial(NameList.TYPE_TCPUSER, server.Username!); + Dial(NameList.TYPE_TCPPASS, server.Password!); - Dial(NameList.TYPE_UDPHOST, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}"); - - if (socks5.Auth()) - { - Dial(NameList.TYPE_TCPUSER, socks5.Username!); - Dial(NameList.TYPE_TCPPASS, socks5.Password!); - - Dial(NameList.TYPE_UDPUSER, socks5.Username!); - Dial(NameList.TYPE_UDPPASS, socks5.Password!); - } - } - else - { - Trace.Assert(false); + Dial(NameList.TYPE_UDPUSER, server.Username!); + Dial(NameList.TYPE_UDPPASS, server.Password!); } #endregion @@ -150,6 +148,7 @@ namespace Netch.Controllers { Global.MainForm.StatusText(i18N.Translate("Setup Route Table Rule")); + var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex); // Server Address if (_serverRemoteAddress != null) RouteUtils.CreateRoute(_outbound.FillTemplate(_serverRemoteAddress.ToString(), 32)); @@ -157,38 +156,22 @@ namespace Netch.Controllers // Global Bypass IPs RouteUtils.CreateRouteFill(_outbound, _tunConfig.BypassIPs); - var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex); - switch (_mode.Type) + // rule + RouteUtils.CreateRouteFill(_tun, _mode.Handle); + RouteUtils.CreateRouteFill(_outbound, _mode.Bypass); + + // dns + // NOTICE: DNS metric is network interface metric + tunNetworkInterface.SetDns(DummyDns); + RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32)); + + if (!_tunConfig.UseCustomDNS) { - case ModeType.ProxyRuleIPs: - // rules - RouteUtils.CreateRouteFill(_tun, _mode.GetRules()); - - if (_tunConfig.ProxyDNS) - { - tunNetworkInterface.SetDns(DummyDns); - // proxy dummy dns - RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32)); - - if (!_tunConfig.UseCustomDNS) - // proxy AioDNS other dns - RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32)); - } - - break; - case ModeType.BypassRuleIPs: - RouteUtils.CreateRouteFill(_outbound, _mode.GetRules()); - - tunNetworkInterface.SetDns(DummyDns); - - if (!_tunConfig.UseCustomDNS) - // bypass AioDNS other dns - RouteUtils.CreateRoute(_outbound.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32)); - - NetworkInterfaceUtils.SetInterfaceMetric(_tun.InterfaceIndex, 0); - RouteUtils.CreateRoute(_tun.FillTemplate("0.0.0.0", 0)); - break; + RouteUtils.CreateRoute(_outbound.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32)); + RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32)); } + + NetworkInterfaceUtils.SetInterfaceMetric(_tun.InterfaceIndex, 0); } private void ClearRouteTable() @@ -198,13 +181,11 @@ namespace Netch.Controllers RouteUtils.DeleteRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs); - switch (_mode.Type) - { - case ModeType.BypassRuleIPs: - RouteUtils.DeleteRouteFill(_outbound, _mode.GetRules()); - NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex); - break; - } + RouteUtils.DeleteRouteFill(_outbound, _mode.Bypass); + + RouteUtils.DeleteRoute(_outbound.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32)); + + NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex); } #endregion diff --git a/Netch/Enums/Modes.cs b/Netch/Enums/Modes.cs deleted file mode 100644 index a3d70445..00000000 --- a/Netch/Enums/Modes.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Netch.Enums -{ - public enum ModeType - { - Process = 0, - ProxyRuleIPs = 1, - BypassRuleIPs = 2, - Pcap2Socks = 6 - } -} \ No newline at end of file diff --git a/Netch/Forms/BindingForm.cs b/Netch/Forms/BindingForm.cs new file mode 100644 index 00000000..968ea48e --- /dev/null +++ b/Netch/Forms/BindingForm.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using Netch.Models; + +namespace Netch.Forms +{ + public class BindingForm : Form + { + private readonly Dictionary> _checkActions = new(); + private readonly Dictionary> _saveActions = new(); + + protected void BindTextBox(TextBoxBase control, Func check, Action save, object value) + { + BindTextBox(control, check, save, value); + } + + protected void BindTextBox(TextBoxBase control, Func check, Action save, object value) + { + control.Text = value.ToString(); + _checkActions.Add(control, + s => + { + try + { + return check.Invoke((T)Convert.ChangeType(s, typeof(T))); + } + catch + { + return false; + } + }); + + _saveActions.Add(control, c => save.Invoke((T)Convert.ChangeType(((TextBoxBase)c).Text, typeof(T)))); + } + + protected void BindCheckBox(CheckBox control, Action save, bool value) + { + control.Checked = value; + _saveActions.Add(control, c => save(((CheckBox)c).Checked)); + } + + protected void BindSyncGlobalCheckBox(SyncGlobalCheckBox control, Action save, bool? value, bool globalValue) + { + control.Value = value; + control.GlobalValue = globalValue; + _saveActions.Add(control, c => save(((SyncGlobalCheckBox)c).Value)); + } + + protected void BindRadioBox(RadioButton control, Action save, bool value) + { + control.Checked = value; + _saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked)); + } + + protected void BindListComboBox(ComboBox comboBox, Action save, IEnumerable values, T value) where T : notnull + { + if (comboBox.DropDownStyle != ComboBoxStyle.DropDownList) + throw new ArgumentOutOfRangeException(); + + var tagItems = values.Select(o => new TagItem(o, o.ToString()!)).ToArray(); + comboBox.Items.AddRange(tagItems.Cast().ToArray()); + + comboBox.ValueMember = nameof(TagItem.Value); + comboBox.DisplayMember = nameof(TagItem.Text); + + _saveActions.Add(comboBox, c => save.Invoke(((TagItem)((ComboBox)c).SelectedItem).Value)); + Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); }; + } + + protected void BindComboBox(ComboBox control, Func check, Action save, string value, object[]? values = null) + { + if (values != null) + control.Items.AddRange(values); + + _saveActions.Add(control, c => save.Invoke(((ComboBox)c).Text)); + _checkActions.Add(control, check.Invoke); + + Load += (_, _) => { control.Text = value; }; + } + + protected List GetCheckFailedControls() + { + return _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)).Select(pair => pair.Key).ToList(); + } + + protected void SaveBinds() + { + foreach (var pair in _saveActions) + pair.Value.Invoke(pair.Key); + } + } +} \ No newline at end of file diff --git a/Netch/Forms/MainForm.Designer.cs b/Netch/Forms/MainForm.Designer.cs index 0002a833..beb8a55e 100644 --- a/Netch/Forms/MainForm.Designer.cs +++ b/Netch/Forms/MainForm.Designer.cs @@ -86,6 +86,7 @@ this.ProfileTable = new System.Windows.Forms.TableLayoutPanel(); this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl(); + this.ReloadModesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MenuStrip.SuspendLayout(); this.ConfigurationGroupBox.SuspendLayout(); this.configLayoutPanel.SuspendLayout(); @@ -144,7 +145,8 @@ // this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.CreateProcessModeToolStripMenuItem, - this.CreateRouteTableRuleToolStripMenuItem}); + this.CreateRouteTableRuleToolStripMenuItem, + this.ReloadModesToolStripMenuItem}); this.ModeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1); this.ModeToolStripMenuItem.Name = "ModeToolStripMenuItem"; this.ModeToolStripMenuItem.Size = new System.Drawing.Size(55, 21); @@ -620,19 +622,19 @@ this.ExitToolStripButton}); this.NotifyMenu.Name = "NotifyMenu"; this.NotifyMenu.ShowItemToolTips = false; - this.NotifyMenu.Size = new System.Drawing.Size(181, 70); + this.NotifyMenu.Size = new System.Drawing.Size(108, 48); // // ShowMainFormToolStripButton // this.ShowMainFormToolStripButton.Name = "ShowMainFormToolStripButton"; - this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(180, 22); + this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(107, 22); this.ShowMainFormToolStripButton.Text = "Show"; this.ShowMainFormToolStripButton.Click += new System.EventHandler(this.ShowMainFormToolStripButton_Click); // // ExitToolStripButton // this.ExitToolStripButton.Name = "ExitToolStripButton"; - this.ExitToolStripButton.Size = new System.Drawing.Size(180, 22); + this.ExitToolStripButton.Size = new System.Drawing.Size(107, 22); this.ExitToolStripButton.Text = "Exit"; this.ExitToolStripButton.Click += new System.EventHandler(this.ExitToolStripButton_Click); // @@ -697,6 +699,13 @@ this.ButtomControlContainerControl.TabStop = false; this.ButtomControlContainerControl.Text = "groupBox1"; // + // ReloadModesToolStripMenuItem + // + this.ReloadModesToolStripMenuItem.Name = "ReloadModesToolStripMenuItem"; + this.ReloadModesToolStripMenuItem.Size = new System.Drawing.Size(217, 22); + this.ReloadModesToolStripMenuItem.Text = "Reload Modes"; + this.ReloadModesToolStripMenuItem.Click += new System.EventHandler(this.ReloadModesToolStripMenuItem_Click); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -804,5 +813,6 @@ private System.Windows.Forms.ContainerControl ButtomControlContainerControl; private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem; private System.Windows.Forms.ToolStripStatusLabel HttpStatusLabel; + private System.Windows.Forms.ToolStripMenuItem ReloadModesToolStripMenuItem; } } \ No newline at end of file diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index 74d228b1..dc89a4d9 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -19,6 +19,7 @@ using Netch.Enums; using Netch.Forms.ModeForms; using Netch.Interfaces; using Netch.Models; +using Netch.Models.Modes; using Netch.Properties; using Netch.Services; using Netch.Utils; @@ -57,7 +58,7 @@ namespace Netch.Forms private void AddAddServerToolStripMenuItems() { foreach (var serversUtil in ServerHelper.ServerUtilDictionary.Values.OrderBy(i => i.Priority) - .Where(i => !string.IsNullOrEmpty(i.FullName))) + .Where(i => !string.IsNullOrEmpty(i.FullName))) { var fullName = serversUtil.FullName; var control = new ToolStripMenuItem @@ -83,10 +84,7 @@ namespace Netch.Forms SelectLastServer(); DelayTestHelper.UpdateTick(true); - ModeHelper.InitWatcher(); - ModeHelper.Load(); - LoadModes(); - SelectLastMode(); + ModeService.Instance.Load(); // 加载翻译 TranslateControls(); @@ -109,7 +107,7 @@ namespace Netch.Forms if (Global.Settings.StartWhenOpened) ControlButton.PerformClick(); - Netch.SingleInstance.ListenForArgumentsFromSuccessiveInstances(); + Program.SingleInstance.ListenForArgumentsFromSuccessiveInstances(); } private void RecordSize() @@ -262,6 +260,19 @@ namespace Netch.Forms Show(); } + private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e) + { + Enabled = false; + try + { + ModeService.Instance.Load(); + } + finally + { + Enabled = true; + } + } + #endregion #region Subscription @@ -395,9 +406,9 @@ namespace Netch.Forms private void ShowHideConsoleToolStripMenuItem_Click(object sender, EventArgs e) { - var windowStyles = (WINDOW_STYLE)PInvoke.GetWindowLong(new HWND(Netch.ConsoleHwnd), WINDOW_LONG_PTR_INDEX.GWL_STYLE); + var windowStyles = (WINDOW_STYLE)PInvoke.GetWindowLong(new HWND(Program.ConsoleHwnd), WINDOW_LONG_PTR_INDEX.GWL_STYLE); var visible = windowStyles.HasFlag(WINDOW_STYLE.WS_VISIBLE); - PInvoke.ShowWindow(Netch.ConsoleHwnd, visible ? SHOW_WINDOW_CMD.SW_HIDE : SHOW_WINDOW_CMD.SW_SHOWNOACTIVATE); + PInvoke.ShowWindow(Program.ConsoleHwnd, visible ? SHOW_WINDOW_CMD.SW_HIDE : SHOW_WINDOW_CMD.SW_SHOWNOACTIVATE); } #endregion @@ -467,7 +478,6 @@ namespace Netch.Forms throw new MessageException(i18N.Translate("The downloaded file has the wrong hash")); } - ModeHelper.SuspendWatcher = true; await StopAsync(); await Configuration.SaveAsync(); @@ -475,7 +485,7 @@ namespace Netch.Forms await Task.Run(updater.ApplyUpdate); // release mutex, exit - Netch.SingleInstance.Dispose(); + Program.SingleInstance.Dispose(); Process.Start(Global.NetchExecutable); Environment.Exit(0); } @@ -768,25 +778,26 @@ namespace Netch.Forms var mode = (Mode)ModeComboBox.SelectedItem; if (ModifierKeys == Keys.Control) { - Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath!)); + Utils.Utils.Open(mode.FullName); return; } switch (mode.Type) { - case ModeType.Process: + case ModeType.ProcessMode: Hide(); new ProcessForm(mode).ShowDialog(); Show(); break; - case ModeType.ProxyRuleIPs: - case ModeType.BypassRuleIPs: + case ModeType.TunMode: Hide(); new RouteForm(mode).ShowDialog(); Show(); break; + case ModeType.ShareMode: + // throw new NotImplementedException(); default: - Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath!)); + Utils.Utils.Open(mode.FullName); break; } } @@ -800,7 +811,7 @@ namespace Netch.Forms return; } - ModeHelper.Delete((Mode)ModeComboBox.SelectedItem); + ModeService.Delete((Mode)ModeComboBox.SelectedItem); SelectLastMode(); } @@ -1492,6 +1503,7 @@ namespace Netch.Forms } case Mode item: { + /* // 绘制 模式Box 底色 e.Graphics.FillRectangle(Brushes.Gray, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height); @@ -1502,6 +1514,7 @@ namespace Netch.Forms new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y), Color.Black, TextFormatFlags.Left); + */ break; } diff --git a/Netch/Forms/ModeForms/ModeEditorUtils.cs b/Netch/Forms/ModeForms/ModeEditorUtils.cs index 7257a490..072cca57 100644 --- a/Netch/Forms/ModeForms/ModeEditorUtils.cs +++ b/Netch/Forms/ModeForms/ModeEditorUtils.cs @@ -20,7 +20,7 @@ namespace Netch.Forms.ModeForms return string.Empty; var safeFileName = ToSafeFileName(name); - var relativePath = $"Custom\\{safeFileName}.txt"; + var relativePath = $"Custom\\{safeFileName}.json"; return relativePath; } } diff --git a/Netch/Forms/ModeForms/ProcessForm.Designer.cs b/Netch/Forms/ModeForms/ProcessForm.Designer.cs index 59db56dc..75f1d920 100644 --- a/Netch/Forms/ModeForms/ProcessForm.Designer.cs +++ b/Netch/Forms/ModeForms/ProcessForm.Designer.cs @@ -32,43 +32,103 @@ namespace Netch.Forms.ModeForms private void InitializeComponent() { this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox(); + this.ConfigurationLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.NamePanel = new System.Windows.Forms.Panel(); this.RemarkLabel = new System.Windows.Forms.Label(); this.RemarkTextBox = new System.Windows.Forms.TextBox(); this.FilenameLabel = new System.Windows.Forms.Label(); this.FilenameTextBox = new System.Windows.Forms.TextBox(); - this.containerControl1 = new System.Windows.Forms.ContainerControl(); - this.RuleRichTextBox = new System.Windows.Forms.RichTextBox(); - this.ProcessGroupBox = new System.Windows.Forms.GroupBox(); - this.SelectButton = new System.Windows.Forms.Button(); - this.ScanButton = new System.Windows.Forms.Button(); - this.ValidationButton = new System.Windows.Forms.Button(); this.ControlButton = new System.Windows.Forms.Button(); + this.OptionsGroupBox = new System.Windows.Forms.GroupBox(); + this.ModeSpecificOptionsLabel = new System.Windows.Forms.Label(); + this.HandleTCPCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.HandleUDPCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.HandleDNSCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.DNSLabel = new System.Windows.Forms.Label(); + this.DNSTextBox = new System.Windows.Forms.TextBox(); + this.HandleProcDNSCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.ProxyDNSCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.HandleICMPCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.ICMPDelayLabel = new System.Windows.Forms.Label(); + this.ICMPDelayTextBox = new System.Windows.Forms.TextBox(); + this.HandleLoopbackCheckBox = new System.Windows.Forms.CheckBox(); + this.HandleLANCheckBox = new System.Windows.Forms.CheckBox(); + this.HandleChildProcCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.RuleTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.ValidationButton = new System.Windows.Forms.Button(); + this.HandleTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.HandleHelperFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.HandleLabel = new System.Windows.Forms.Label(); + this.HandleSelectButton = new System.Windows.Forms.Button(); + this.HandleScanButton = new System.Windows.Forms.Button(); + this.HandleContentTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.HandleRuleRichTextBox = new System.Windows.Forms.RichTextBox(); + this.BypassTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.BypassFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.BypassLabel = new System.Windows.Forms.Label(); + this.BypassSelectButton = new System.Windows.Forms.Button(); + this.BypassScanButton = new System.Windows.Forms.Button(); + this.BypassContentTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.BypassRuleRichTextBox = new System.Windows.Forms.RichTextBox(); this.ConfigurationGroupBox.SuspendLayout(); - this.containerControl1.SuspendLayout(); - this.ProcessGroupBox.SuspendLayout(); + this.ConfigurationLayoutPanel.SuspendLayout(); + this.NamePanel.SuspendLayout(); + this.OptionsGroupBox.SuspendLayout(); + this.RuleTableLayoutPanel.SuspendLayout(); + this.HandleTableLayoutPanel.SuspendLayout(); + this.HandleHelperFlowLayoutPanel.SuspendLayout(); + this.HandleContentTableLayoutPanel.SuspendLayout(); + this.BypassTableLayoutPanel.SuspendLayout(); + this.BypassFlowLayoutPanel.SuspendLayout(); + this.BypassContentTableLayoutPanel.SuspendLayout(); this.SuspendLayout(); // // ConfigurationGroupBox // - this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel); - this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox); - this.ConfigurationGroupBox.Controls.Add(this.FilenameLabel); - this.ConfigurationGroupBox.Controls.Add(this.FilenameTextBox); - this.ConfigurationGroupBox.Controls.Add(this.containerControl1); - this.ConfigurationGroupBox.Controls.Add(this.ProcessGroupBox); - this.ConfigurationGroupBox.Controls.Add(this.ControlButton); + this.ConfigurationGroupBox.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ConfigurationGroupBox.Controls.Add(this.ConfigurationLayoutPanel); this.ConfigurationGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; - this.ConfigurationGroupBox.Location = new System.Drawing.Point(12, 5); + this.ConfigurationGroupBox.Location = new System.Drawing.Point(0, 0); this.ConfigurationGroupBox.Name = "ConfigurationGroupBox"; - this.ConfigurationGroupBox.Size = new System.Drawing.Size(431, 378); + this.ConfigurationGroupBox.Size = new System.Drawing.Size(934, 591); this.ConfigurationGroupBox.TabIndex = 0; this.ConfigurationGroupBox.TabStop = false; this.ConfigurationGroupBox.Text = "Configuration"; // + // ConfigurationLayoutPanel + // + this.ConfigurationLayoutPanel.ColumnCount = 1; + this.ConfigurationLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.ConfigurationLayoutPanel.Controls.Add(this.NamePanel, 0, 0); + this.ConfigurationLayoutPanel.Controls.Add(this.OptionsGroupBox, 0, 1); + this.ConfigurationLayoutPanel.Controls.Add(this.RuleTableLayoutPanel, 0, 2); + this.ConfigurationLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.ConfigurationLayoutPanel.Location = new System.Drawing.Point(3, 19); + this.ConfigurationLayoutPanel.Name = "ConfigurationLayoutPanel"; + this.ConfigurationLayoutPanel.RowCount = 3; + this.ConfigurationLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.ConfigurationLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.ConfigurationLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.ConfigurationLayoutPanel.Size = new System.Drawing.Size(928, 569); + this.ConfigurationLayoutPanel.TabIndex = 0; + // + // NamePanel + // + this.NamePanel.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.NamePanel.Controls.Add(this.RemarkLabel); + this.NamePanel.Controls.Add(this.RemarkTextBox); + this.NamePanel.Controls.Add(this.FilenameLabel); + this.NamePanel.Controls.Add(this.FilenameTextBox); + this.NamePanel.Controls.Add(this.ControlButton); + this.NamePanel.Location = new System.Drawing.Point(208, 3); + this.NamePanel.Name = "NamePanel"; + this.NamePanel.Size = new System.Drawing.Size(512, 72); + this.NamePanel.TabIndex = 0; + // // RemarkLabel // this.RemarkLabel.AutoSize = true; - this.RemarkLabel.Location = new System.Drawing.Point(12, 25); + this.RemarkLabel.Location = new System.Drawing.Point(8, 8); this.RemarkLabel.Name = "RemarkLabel"; this.RemarkLabel.Size = new System.Drawing.Size(53, 17); this.RemarkLabel.TabIndex = 0; @@ -76,7 +136,7 @@ namespace Netch.Forms.ModeForms // // RemarkTextBox // - this.RemarkTextBox.Location = new System.Drawing.Point(84, 22); + this.RemarkTextBox.Location = new System.Drawing.Point(72, 8); this.RemarkTextBox.Name = "RemarkTextBox"; this.RemarkTextBox.Size = new System.Drawing.Size(341, 23); this.RemarkTextBox.TabIndex = 1; @@ -85,7 +145,7 @@ namespace Netch.Forms.ModeForms // FilenameLabel // this.FilenameLabel.AutoSize = true; - this.FilenameLabel.Location = new System.Drawing.Point(12, 55); + this.FilenameLabel.Location = new System.Drawing.Point(8, 40); this.FilenameLabel.Name = "FilenameLabel"; this.FilenameLabel.Size = new System.Drawing.Size(59, 17); this.FilenameLabel.TabIndex = 2; @@ -93,119 +153,491 @@ namespace Netch.Forms.ModeForms // // FilenameTextBox // - this.FilenameTextBox.Location = new System.Drawing.Point(84, 52); + this.FilenameTextBox.Location = new System.Drawing.Point(72, 40); this.FilenameTextBox.Name = "FilenameTextBox"; this.FilenameTextBox.ReadOnly = true; this.FilenameTextBox.Size = new System.Drawing.Size(341, 23); this.FilenameTextBox.TabIndex = 3; // - // containerControl1 - // - this.containerControl1.Controls.Add(this.RuleRichTextBox); - this.containerControl1.Location = new System.Drawing.Point(6, 81); - this.containerControl1.Name = "containerControl1"; - this.containerControl1.Size = new System.Drawing.Size(419, 221); - this.containerControl1.TabIndex = 4; - this.containerControl1.Text = "containerControl1"; - // - // RuleRichTextBox - // - this.RuleRichTextBox.DetectUrls = false; - this.RuleRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill; - this.RuleRichTextBox.Location = new System.Drawing.Point(0, 0); - this.RuleRichTextBox.Name = "RuleRichTextBox"; - this.RuleRichTextBox.Size = new System.Drawing.Size(419, 221); - this.RuleRichTextBox.TabIndex = 0; - this.RuleRichTextBox.Text = ""; - this.RuleRichTextBox.WordWrap = false; - // - // ProcessGroupBox - // - this.ProcessGroupBox.Controls.Add(this.SelectButton); - this.ProcessGroupBox.Controls.Add(this.ScanButton); - this.ProcessGroupBox.Controls.Add(this.ValidationButton); - this.ProcessGroupBox.Location = new System.Drawing.Point(6, 295); - this.ProcessGroupBox.Name = "ProcessGroupBox"; - this.ProcessGroupBox.Size = new System.Drawing.Size(419, 44); - this.ProcessGroupBox.TabIndex = 5; - this.ProcessGroupBox.TabStop = false; - // - // SelectButton - // - this.SelectButton.Location = new System.Drawing.Point(6, 13); - this.SelectButton.Name = "SelectButton"; - this.SelectButton.Size = new System.Drawing.Size(75, 23); - this.SelectButton.TabIndex = 0; - this.SelectButton.Text = "Select"; - this.SelectButton.UseVisualStyleBackColor = true; - this.SelectButton.Click += new System.EventHandler(this.SelectButton_Click); - // - // ScanButton - // - this.ScanButton.Location = new System.Drawing.Point(87, 13); - this.ScanButton.Name = "ScanButton"; - this.ScanButton.Size = new System.Drawing.Size(75, 23); - this.ScanButton.TabIndex = 1; - this.ScanButton.Text = "Scan"; - this.ScanButton.UseVisualStyleBackColor = true; - this.ScanButton.Click += new System.EventHandler(this.ScanButton_Click); - // - // ValidationButton - // - this.ValidationButton.Location = new System.Drawing.Point(338, 13); - this.ValidationButton.Name = "ValidationButton"; - this.ValidationButton.Size = new System.Drawing.Size(75, 23); - this.ValidationButton.TabIndex = 2; - this.ValidationButton.Text = "Validation"; - this.ValidationButton.UseVisualStyleBackColor = true; - this.ValidationButton.Click += new System.EventHandler(this.ValidationButton_Click); - // // ControlButton // - this.ControlButton.Location = new System.Drawing.Point(344, 345); + this.ControlButton.Location = new System.Drawing.Point(424, 40); this.ControlButton.Name = "ControlButton"; this.ControlButton.Size = new System.Drawing.Size(75, 23); - this.ControlButton.TabIndex = 6; + this.ControlButton.TabIndex = 4; this.ControlButton.Text = "Save"; this.ControlButton.UseVisualStyleBackColor = true; this.ControlButton.Click += new System.EventHandler(this.ControlButton_Click); // - // Process + // OptionsGroupBox + // + this.OptionsGroupBox.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.OptionsGroupBox.Controls.Add(this.ModeSpecificOptionsLabel); + this.OptionsGroupBox.Controls.Add(this.HandleTCPCheckBox); + this.OptionsGroupBox.Controls.Add(this.HandleUDPCheckBox); + this.OptionsGroupBox.Controls.Add(this.HandleDNSCheckBox); + this.OptionsGroupBox.Controls.Add(this.DNSLabel); + this.OptionsGroupBox.Controls.Add(this.DNSTextBox); + this.OptionsGroupBox.Controls.Add(this.HandleProcDNSCheckBox); + this.OptionsGroupBox.Controls.Add(this.ProxyDNSCheckBox); + this.OptionsGroupBox.Controls.Add(this.HandleICMPCheckBox); + this.OptionsGroupBox.Controls.Add(this.ICMPDelayLabel); + this.OptionsGroupBox.Controls.Add(this.ICMPDelayTextBox); + this.OptionsGroupBox.Controls.Add(this.HandleLoopbackCheckBox); + this.OptionsGroupBox.Controls.Add(this.HandleLANCheckBox); + this.OptionsGroupBox.Controls.Add(this.HandleChildProcCheckBox); + this.OptionsGroupBox.Location = new System.Drawing.Point(15, 81); + this.OptionsGroupBox.Name = "OptionsGroupBox"; + this.OptionsGroupBox.Size = new System.Drawing.Size(898, 183); + this.OptionsGroupBox.TabIndex = 1; + this.OptionsGroupBox.TabStop = false; + // + // ModeSpecificOptionsLabel + // + this.ModeSpecificOptionsLabel.AutoSize = true; + this.ModeSpecificOptionsLabel.Location = new System.Drawing.Point(720, 24); + this.ModeSpecificOptionsLabel.Name = "ModeSpecificOptionsLabel"; + this.ModeSpecificOptionsLabel.Size = new System.Drawing.Size(138, 17); + this.ModeSpecificOptionsLabel.TabIndex = 13; + this.ModeSpecificOptionsLabel.Text = "Mode specific options"; + // + // HandleTCPCheckBox + // + this.HandleTCPCheckBox.AutoCheck = false; + this.HandleTCPCheckBox.AutoSize = true; + this.HandleTCPCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleTCPCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleTCPCheckBox.GlobalValue = false; + this.HandleTCPCheckBox.Location = new System.Drawing.Point(8, 24); + this.HandleTCPCheckBox.Name = "HandleTCPCheckBox"; + this.HandleTCPCheckBox.Size = new System.Drawing.Size(99, 21); + this.HandleTCPCheckBox.SyncGlobal = false; + this.HandleTCPCheckBox.TabIndex = 0; + this.HandleTCPCheckBox.Text = "Handle TCP"; + this.HandleTCPCheckBox.ThreeState = true; + this.HandleTCPCheckBox.UseVisualStyleBackColor = true; + this.HandleTCPCheckBox.Value = false; + // + // HandleUDPCheckBox + // + this.HandleUDPCheckBox.AutoCheck = false; + this.HandleUDPCheckBox.AutoSize = true; + this.HandleUDPCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleUDPCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleUDPCheckBox.GlobalValue = false; + this.HandleUDPCheckBox.Location = new System.Drawing.Point(8, 56); + this.HandleUDPCheckBox.Name = "HandleUDPCheckBox"; + this.HandleUDPCheckBox.Size = new System.Drawing.Size(102, 21); + this.HandleUDPCheckBox.SyncGlobal = false; + this.HandleUDPCheckBox.TabIndex = 1; + this.HandleUDPCheckBox.Text = "Handle UDP"; + this.HandleUDPCheckBox.ThreeState = true; + this.HandleUDPCheckBox.UseVisualStyleBackColor = true; + this.HandleUDPCheckBox.Value = false; + // + // HandleDNSCheckBox + // + this.HandleDNSCheckBox.AutoCheck = false; + this.HandleDNSCheckBox.AutoSize = true; + this.HandleDNSCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleDNSCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleDNSCheckBox.GlobalValue = false; + this.HandleDNSCheckBox.Location = new System.Drawing.Point(8, 88); + this.HandleDNSCheckBox.Name = "HandleDNSCheckBox"; + this.HandleDNSCheckBox.Size = new System.Drawing.Size(203, 21); + this.HandleDNSCheckBox.SyncGlobal = false; + this.HandleDNSCheckBox.TabIndex = 2; + this.HandleDNSCheckBox.Text = "Handle DNS (DNS hijacking)"; + this.HandleDNSCheckBox.ThreeState = true; + this.HandleDNSCheckBox.UseVisualStyleBackColor = true; + this.HandleDNSCheckBox.Value = false; + // + // DNSLabel + // + this.DNSLabel.AutoSize = true; + this.DNSLabel.Location = new System.Drawing.Point(248, 88); + this.DNSLabel.Name = "DNSLabel"; + this.DNSLabel.Size = new System.Drawing.Size(34, 17); + this.DNSLabel.TabIndex = 3; + this.DNSLabel.Text = "DNS"; + // + // DNSTextBox + // + this.DNSTextBox.Location = new System.Drawing.Point(296, 88); + this.DNSTextBox.Name = "DNSTextBox"; + this.DNSTextBox.Size = new System.Drawing.Size(184, 23); + this.DNSTextBox.TabIndex = 4; + this.DNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // HandleProcDNSCheckBox + // + this.HandleProcDNSCheckBox.AutoCheck = false; + this.HandleProcDNSCheckBox.AutoSize = true; + this.HandleProcDNSCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleProcDNSCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleProcDNSCheckBox.GlobalValue = false; + this.HandleProcDNSCheckBox.Location = new System.Drawing.Point(8, 120); + this.HandleProcDNSCheckBox.Name = "HandleProcDNSCheckBox"; + this.HandleProcDNSCheckBox.Size = new System.Drawing.Size(216, 21); + this.HandleProcDNSCheckBox.SyncGlobal = false; + this.HandleProcDNSCheckBox.TabIndex = 5; + this.HandleProcDNSCheckBox.Text = "Handle handled process\'s DNS"; + this.HandleProcDNSCheckBox.ThreeState = true; + this.HandleProcDNSCheckBox.UseVisualStyleBackColor = true; + this.HandleProcDNSCheckBox.Value = false; + // + // ProxyDNSCheckBox + // + this.ProxyDNSCheckBox.AutoCheck = false; + this.ProxyDNSCheckBox.AutoSize = true; + this.ProxyDNSCheckBox.BackColor = System.Drawing.Color.Yellow; + this.ProxyDNSCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.ProxyDNSCheckBox.GlobalValue = false; + this.ProxyDNSCheckBox.Location = new System.Drawing.Point(240, 120); + this.ProxyDNSCheckBox.Name = "ProxyDNSCheckBox"; + this.ProxyDNSCheckBox.Size = new System.Drawing.Size(195, 21); + this.ProxyDNSCheckBox.SyncGlobal = false; + this.ProxyDNSCheckBox.TabIndex = 6; + this.ProxyDNSCheckBox.Text = "Handle DNS through proxy"; + this.ProxyDNSCheckBox.ThreeState = true; + this.ProxyDNSCheckBox.UseVisualStyleBackColor = true; + this.ProxyDNSCheckBox.Value = false; + // + // HandleICMPCheckBox + // + this.HandleICMPCheckBox.AutoCheck = false; + this.HandleICMPCheckBox.AutoSize = true; + this.HandleICMPCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleICMPCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleICMPCheckBox.GlobalValue = false; + this.HandleICMPCheckBox.Location = new System.Drawing.Point(8, 152); + this.HandleICMPCheckBox.Name = "HandleICMPCheckBox"; + this.HandleICMPCheckBox.Size = new System.Drawing.Size(107, 21); + this.HandleICMPCheckBox.SyncGlobal = false; + this.HandleICMPCheckBox.TabIndex = 7; + this.HandleICMPCheckBox.Text = "Handle ICMP"; + this.HandleICMPCheckBox.ThreeState = true; + this.HandleICMPCheckBox.UseVisualStyleBackColor = true; + this.HandleICMPCheckBox.Value = false; + // + // ICMPDelayLabel + // + this.ICMPDelayLabel.AutoSize = true; + this.ICMPDelayLabel.Location = new System.Drawing.Point(176, 152); + this.ICMPDelayLabel.Name = "ICMPDelayLabel"; + this.ICMPDelayLabel.Size = new System.Drawing.Size(99, 17); + this.ICMPDelayLabel.TabIndex = 8; + this.ICMPDelayLabel.Text = "ICMP delay(ms)"; + // + // ICMPDelayTextBox + // + this.ICMPDelayTextBox.Location = new System.Drawing.Point(296, 152); + this.ICMPDelayTextBox.Name = "ICMPDelayTextBox"; + this.ICMPDelayTextBox.Size = new System.Drawing.Size(80, 23); + this.ICMPDelayTextBox.TabIndex = 9; + this.ICMPDelayTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // HandleLoopbackCheckBox + // + this.HandleLoopbackCheckBox.AutoSize = true; + this.HandleLoopbackCheckBox.Location = new System.Drawing.Point(720, 56); + this.HandleLoopbackCheckBox.Name = "HandleLoopbackCheckBox"; + this.HandleLoopbackCheckBox.Size = new System.Drawing.Size(158, 21); + this.HandleLoopbackCheckBox.TabIndex = 10; + this.HandleLoopbackCheckBox.Text = "Handle local loopback"; + this.HandleLoopbackCheckBox.UseVisualStyleBackColor = true; + // + // HandleLANCheckBox + // + this.HandleLANCheckBox.AutoSize = true; + this.HandleLANCheckBox.Location = new System.Drawing.Point(720, 88); + this.HandleLANCheckBox.Name = "HandleLANCheckBox"; + this.HandleLANCheckBox.Size = new System.Drawing.Size(96, 21); + this.HandleLANCheckBox.TabIndex = 11; + this.HandleLANCheckBox.Text = "Handle LAN"; + this.HandleLANCheckBox.UseVisualStyleBackColor = true; + // + // HandleChildProcCheckBox + // + this.HandleChildProcCheckBox.AutoCheck = false; + this.HandleChildProcCheckBox.AutoSize = true; + this.HandleChildProcCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleChildProcCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleChildProcCheckBox.GlobalValue = false; + this.HandleChildProcCheckBox.Location = new System.Drawing.Point(496, 24); + this.HandleChildProcCheckBox.Name = "HandleChildProcCheckBox"; + this.HandleChildProcCheckBox.Size = new System.Drawing.Size(155, 21); + this.HandleChildProcCheckBox.SyncGlobal = false; + this.HandleChildProcCheckBox.TabIndex = 12; + this.HandleChildProcCheckBox.Text = "Handle child process"; + this.HandleChildProcCheckBox.ThreeState = true; + this.HandleChildProcCheckBox.UseVisualStyleBackColor = true; + this.HandleChildProcCheckBox.Value = false; + // + // RuleTableLayoutPanel + // + this.RuleTableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.RuleTableLayoutPanel.ColumnCount = 2; + this.RuleTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.RuleTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.RuleTableLayoutPanel.Controls.Add(this.ValidationButton, 0, 0); + this.RuleTableLayoutPanel.Controls.Add(this.HandleTableLayoutPanel, 0, 1); + this.RuleTableLayoutPanel.Controls.Add(this.BypassTableLayoutPanel, 1, 1); + this.RuleTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.RuleTableLayoutPanel.Location = new System.Drawing.Point(3, 270); + this.RuleTableLayoutPanel.Name = "RuleTableLayoutPanel"; + this.RuleTableLayoutPanel.RowCount = 2; + this.RuleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.RuleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.RuleTableLayoutPanel.Size = new System.Drawing.Size(922, 296); + this.RuleTableLayoutPanel.TabIndex = 2; + // + // ValidationButton + // + this.ValidationButton.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.RuleTableLayoutPanel.SetColumnSpan(this.ValidationButton, 2); + this.ValidationButton.Location = new System.Drawing.Point(423, 3); + this.ValidationButton.Name = "ValidationButton"; + this.ValidationButton.Size = new System.Drawing.Size(75, 23); + this.ValidationButton.TabIndex = 0; + this.ValidationButton.Text = "Validation"; + this.ValidationButton.UseVisualStyleBackColor = true; + this.ValidationButton.Click += new System.EventHandler(this.ValidationButton_Click); + // + // HandleTableLayoutPanel + // + this.HandleTableLayoutPanel.ColumnCount = 1; + this.HandleTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.HandleTableLayoutPanel.Controls.Add(this.HandleHelperFlowLayoutPanel, 0, 0); + this.HandleTableLayoutPanel.Controls.Add(this.HandleContentTableLayoutPanel, 0, 1); + this.HandleTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.HandleTableLayoutPanel.Location = new System.Drawing.Point(3, 32); + this.HandleTableLayoutPanel.Name = "HandleTableLayoutPanel"; + this.HandleTableLayoutPanel.RowCount = 2; + this.HandleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.HandleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.HandleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.HandleTableLayoutPanel.Size = new System.Drawing.Size(455, 261); + this.HandleTableLayoutPanel.TabIndex = 1; + // + // HandleHelperFlowLayoutPanel + // + this.HandleHelperFlowLayoutPanel.Controls.Add(this.HandleLabel); + this.HandleHelperFlowLayoutPanel.Controls.Add(this.HandleSelectButton); + this.HandleHelperFlowLayoutPanel.Controls.Add(this.HandleScanButton); + this.HandleHelperFlowLayoutPanel.Location = new System.Drawing.Point(3, 3); + this.HandleHelperFlowLayoutPanel.Name = "HandleHelperFlowLayoutPanel"; + this.HandleHelperFlowLayoutPanel.Size = new System.Drawing.Size(269, 32); + this.HandleHelperFlowLayoutPanel.TabIndex = 0; + // + // HandleLabel + // + this.HandleLabel.AutoSize = true; + this.HandleLabel.Location = new System.Drawing.Point(3, 0); + this.HandleLabel.Name = "HandleLabel"; + this.HandleLabel.Padding = new System.Windows.Forms.Padding(7); + this.HandleLabel.Size = new System.Drawing.Size(95, 31); + this.HandleLabel.TabIndex = 0; + this.HandleLabel.Text = "Handle rules"; + // + // HandleSelectButton + // + this.HandleSelectButton.Location = new System.Drawing.Point(104, 3); + this.HandleSelectButton.Name = "HandleSelectButton"; + this.HandleSelectButton.Size = new System.Drawing.Size(75, 23); + this.HandleSelectButton.TabIndex = 1; + this.HandleSelectButton.Text = "Select"; + this.HandleSelectButton.UseVisualStyleBackColor = true; + this.HandleSelectButton.Click += new System.EventHandler(this.SelectButton_Click); + // + // HandleScanButton + // + this.HandleHelperFlowLayoutPanel.SetFlowBreak(this.HandleScanButton, true); + this.HandleScanButton.Location = new System.Drawing.Point(185, 3); + this.HandleScanButton.Name = "HandleScanButton"; + this.HandleScanButton.Size = new System.Drawing.Size(75, 23); + this.HandleScanButton.TabIndex = 2; + this.HandleScanButton.Text = "Scan"; + this.HandleScanButton.UseVisualStyleBackColor = true; + this.HandleScanButton.Click += new System.EventHandler(this.ScanButton_Click); + // + // HandleContentTableLayoutPanel + // + this.HandleContentTableLayoutPanel.ColumnCount = 1; + this.HandleContentTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.HandleContentTableLayoutPanel.Controls.Add(this.HandleRuleRichTextBox, 0, 0); + this.HandleContentTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.HandleContentTableLayoutPanel.Location = new System.Drawing.Point(3, 41); + this.HandleContentTableLayoutPanel.Name = "HandleContentTableLayoutPanel"; + this.HandleContentTableLayoutPanel.RowCount = 1; + this.HandleContentTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.HandleContentTableLayoutPanel.Size = new System.Drawing.Size(449, 217); + this.HandleContentTableLayoutPanel.TabIndex = 1; + // + // HandleRuleRichTextBox + // + this.HandleRuleRichTextBox.DetectUrls = false; + this.HandleRuleRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.HandleRuleRichTextBox.Location = new System.Drawing.Point(3, 3); + this.HandleRuleRichTextBox.Name = "HandleRuleRichTextBox"; + this.HandleRuleRichTextBox.Size = new System.Drawing.Size(443, 211); + this.HandleRuleRichTextBox.TabIndex = 0; + this.HandleRuleRichTextBox.Text = ""; + this.HandleRuleRichTextBox.WordWrap = false; + // + // BypassTableLayoutPanel + // + this.BypassTableLayoutPanel.ColumnCount = 1; + this.BypassTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.BypassTableLayoutPanel.Controls.Add(this.BypassFlowLayoutPanel, 0, 0); + this.BypassTableLayoutPanel.Controls.Add(this.BypassContentTableLayoutPanel, 0, 1); + this.BypassTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.BypassTableLayoutPanel.Location = new System.Drawing.Point(464, 32); + this.BypassTableLayoutPanel.Name = "BypassTableLayoutPanel"; + this.BypassTableLayoutPanel.RowCount = 2; + this.BypassTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.BypassTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.BypassTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.BypassTableLayoutPanel.Size = new System.Drawing.Size(455, 261); + this.BypassTableLayoutPanel.TabIndex = 2; + // + // BypassFlowLayoutPanel + // + this.BypassFlowLayoutPanel.Controls.Add(this.BypassLabel); + this.BypassFlowLayoutPanel.Controls.Add(this.BypassSelectButton); + this.BypassFlowLayoutPanel.Controls.Add(this.BypassScanButton); + this.BypassFlowLayoutPanel.Location = new System.Drawing.Point(3, 3); + this.BypassFlowLayoutPanel.Name = "BypassFlowLayoutPanel"; + this.BypassFlowLayoutPanel.Size = new System.Drawing.Size(269, 32); + this.BypassFlowLayoutPanel.TabIndex = 0; + // + // BypassLabel + // + this.BypassLabel.AutoSize = true; + this.BypassLabel.Location = new System.Drawing.Point(3, 0); + this.BypassLabel.Name = "BypassLabel"; + this.BypassLabel.Padding = new System.Windows.Forms.Padding(7); + this.BypassLabel.Size = new System.Drawing.Size(95, 31); + this.BypassLabel.TabIndex = 0; + this.BypassLabel.Text = "Bypass rules"; + // + // BypassSelectButton + // + this.BypassSelectButton.Location = new System.Drawing.Point(104, 3); + this.BypassSelectButton.Name = "BypassSelectButton"; + this.BypassSelectButton.Size = new System.Drawing.Size(75, 23); + this.BypassSelectButton.TabIndex = 1; + this.BypassSelectButton.Text = "Select"; + this.BypassSelectButton.UseVisualStyleBackColor = true; + this.BypassSelectButton.Click += new System.EventHandler(this.SelectButton_Click); + // + // BypassScanButton + // + this.BypassScanButton.Location = new System.Drawing.Point(185, 3); + this.BypassScanButton.Name = "BypassScanButton"; + this.BypassScanButton.Size = new System.Drawing.Size(75, 23); + this.BypassScanButton.TabIndex = 2; + this.BypassScanButton.Text = "Scan"; + this.BypassScanButton.UseVisualStyleBackColor = true; + this.BypassScanButton.Click += new System.EventHandler(this.ScanButton_Click); + // + // BypassContentTableLayoutPanel + // + this.BypassContentTableLayoutPanel.ColumnCount = 1; + this.BypassContentTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.BypassContentTableLayoutPanel.Controls.Add(this.BypassRuleRichTextBox, 0, 0); + this.BypassContentTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.BypassContentTableLayoutPanel.Location = new System.Drawing.Point(3, 41); + this.BypassContentTableLayoutPanel.Name = "BypassContentTableLayoutPanel"; + this.BypassContentTableLayoutPanel.RowCount = 1; + this.BypassContentTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.BypassContentTableLayoutPanel.Size = new System.Drawing.Size(449, 217); + this.BypassContentTableLayoutPanel.TabIndex = 1; + // + // BypassRuleRichTextBox + // + this.BypassRuleRichTextBox.DetectUrls = false; + this.BypassRuleRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.BypassRuleRichTextBox.Location = new System.Drawing.Point(3, 3); + this.BypassRuleRichTextBox.Name = "BypassRuleRichTextBox"; + this.BypassRuleRichTextBox.Size = new System.Drawing.Size(443, 211); + this.BypassRuleRichTextBox.TabIndex = 0; + this.BypassRuleRichTextBox.Text = ""; + this.BypassRuleRichTextBox.WordWrap = false; + // + // ProcessForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(455, 388); + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(934, 591); this.Controls.Add(this.ConfigurationGroupBox); - this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); - this.MaximizeBox = false; + this.MinimumSize = new System.Drawing.Size(950, 630); this.Name = "ProcessForm"; - this.Padding = new System.Windows.Forms.Padding(12, 5, 12, 5); this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Create Process Mode"; this.Load += new System.EventHandler(this.ModeForm_Load); this.ConfigurationGroupBox.ResumeLayout(false); - this.ConfigurationGroupBox.PerformLayout(); - this.containerControl1.ResumeLayout(false); - this.ProcessGroupBox.ResumeLayout(false); + this.ConfigurationLayoutPanel.ResumeLayout(false); + this.NamePanel.ResumeLayout(false); + this.NamePanel.PerformLayout(); + this.OptionsGroupBox.ResumeLayout(false); + this.OptionsGroupBox.PerformLayout(); + this.RuleTableLayoutPanel.ResumeLayout(false); + this.HandleTableLayoutPanel.ResumeLayout(false); + this.HandleHelperFlowLayoutPanel.ResumeLayout(false); + this.HandleHelperFlowLayoutPanel.PerformLayout(); + this.HandleContentTableLayoutPanel.ResumeLayout(false); + this.BypassTableLayoutPanel.ResumeLayout(false); + this.BypassFlowLayoutPanel.ResumeLayout(false); + this.BypassFlowLayoutPanel.PerformLayout(); + this.BypassContentTableLayoutPanel.ResumeLayout(false); this.ResumeLayout(false); } #endregion - private System.Windows.Forms.Button ScanButton; - private System.Windows.Forms.ContainerControl containerControl1; + private System.Windows.Forms.Button HandleScanButton; public System.Windows.Forms.GroupBox ConfigurationGroupBox; private System.Windows.Forms.Label RemarkLabel; - private System.Windows.Forms.GroupBox ProcessGroupBox; private System.Windows.Forms.TextBox RemarkTextBox; - private System.Windows.Forms.Button SelectButton; + private System.Windows.Forms.Button HandleSelectButton; public System.Windows.Forms.Button ControlButton; private System.Windows.Forms.Label FilenameLabel; private System.Windows.Forms.TextBox FilenameTextBox; - private RichTextBox RuleRichTextBox; + private RichTextBox HandleRuleRichTextBox; private Button ValidationButton; + private RichTextBox BypassRuleRichTextBox; + private Button BypassSelectButton; + private Button BypassScanButton; + private Label BypassLabel; + private Label HandleLabel; + private GroupBox OptionsGroupBox; + private SyncGlobalCheckBox ProxyDNSCheckBox; + private SyncGlobalCheckBox HandleDNSCheckBox; + private SyncGlobalCheckBox HandleUDPCheckBox; + private SyncGlobalCheckBox HandleTCPCheckBox; + private CheckBox HandleLANCheckBox; + private CheckBox HandleLoopbackCheckBox; + private TextBox ICMPDelayTextBox; + private TextBox DNSTextBox; + private SyncGlobalCheckBox HandleICMPCheckBox; + private SyncGlobalCheckBox HandleProcDNSCheckBox; + private Label ICMPDelayLabel; + private Label DNSLabel; + private FlowLayoutPanel BypassFlowLayoutPanel; + private FlowLayoutPanel HandleHelperFlowLayoutPanel; + private TableLayoutPanel ConfigurationLayoutPanel; + private Panel NamePanel; + private TableLayoutPanel HandleTableLayoutPanel; + private TableLayoutPanel RuleTableLayoutPanel; + private TableLayoutPanel BypassTableLayoutPanel; + private TableLayoutPanel HandleContentTableLayoutPanel; + private TableLayoutPanel BypassContentTableLayoutPanel; + private SyncGlobalCheckBox HandleChildProcCheckBox; + private Label ModeSpecificOptionsLabel; } } \ No newline at end of file diff --git a/Netch/Forms/ModeForms/ProcessForm.cs b/Netch/Forms/ModeForms/ProcessForm.cs index cffbe6a9..d7396879 100644 --- a/Netch/Forms/ModeForms/ProcessForm.cs +++ b/Netch/Forms/ModeForms/ProcessForm.cs @@ -1,23 +1,24 @@ -using Microsoft.WindowsAPICodePack.Dialogs; -using Netch.Controllers; -using Netch.Models; -using Netch.Properties; -using Netch.Utils; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; using System.Windows.Forms; +using Netch.Controllers; using Netch.Enums; +using Netch.Models.Modes; +using Netch.Models.Modes.ProcessMode; +using Netch.Properties; +using Netch.Services; +using Netch.Utils; namespace Netch.Forms.ModeForms { - public partial class ProcessForm : Form + public partial class ProcessForm : BindingForm { - /// - /// 被编辑的模式 - /// - private readonly Mode? _mode; + private readonly bool IsCreateMode; + + private readonly Redirector _mode; /// /// 编辑模式 @@ -25,131 +26,141 @@ namespace Netch.Forms.ModeForms /// 模式 public ProcessForm(Mode? mode = null) { - if (mode != null && mode.Type is not ModeType.Process) - throw new ArgumentOutOfRangeException(); + switch (mode) + { + case Redirector processMode: + IsCreateMode = false; + _mode = processMode; + break; + case null: + IsCreateMode = true; + _mode = new Redirector(); + break; + default: + throw new ArgumentOutOfRangeException(); + } InitializeComponent(); Icon = Resources.icon; - CheckForIllegalCrossThreadCalls = false; + InitBindings(); - _mode = mode; + var g = Global.Settings.Redirector; + BindTextBox(RemarkTextBox, _ => true, s => _mode.i18NRemark = s, _mode.i18NRemark); + BindSyncGlobalCheckBox(HandleTCPCheckBox, b => _mode.FilterTCP = b, _mode.FilterTCP, g.FilterTCP); + BindSyncGlobalCheckBox(HandleUDPCheckBox, b => _mode.FilterUDP = b, _mode.FilterUDP, g.FilterUDP); + BindSyncGlobalCheckBox(HandleDNSCheckBox, b => _mode.FilterDNS = b, _mode.FilterDNS, g.FilterDNS); + BindTextBox(DNSTextBox, s => IPEndPoint.TryParse(s, out _), s => _mode.DNSHost = s, _mode.DNSHost ?? Constants.DefaultPrimaryDNS); + + BindSyncGlobalCheckBox(HandleProcDNSCheckBox, b => _mode.HandleOnlyDNS = b, _mode.HandleOnlyDNS, g.HandleOnlyDNS); + BindSyncGlobalCheckBox(ProxyDNSCheckBox, b => _mode.DNSProxy = b, _mode.DNSProxy, g.DNSProxy); + BindSyncGlobalCheckBox(HandleICMPCheckBox, b => _mode.FilterICMP = b, _mode.FilterICMP, g.FilterICMP); + BindTextBox(ICMPDelayTextBox, s => s >= 0, s => _mode.ICMPDelay = s, _mode.ICMPDelay ?? 10); + BindCheckBox(HandleLoopbackCheckBox, b => _mode.FilterLoopback = b, _mode.FilterLoopback); + BindCheckBox(HandleLANCheckBox, b => _mode.FilterIntranet = b, _mode.FilterIntranet); + BindSyncGlobalCheckBox(HandleChildProcCheckBox, b => _mode.FilterParent = b, _mode.FilterParent, g.FilterParent); + + BindTextBox(BypassRuleRichTextBox, s => true, s => _mode.Bypass = s.GetLines().ToList(), string.Join(Constants.EOF, _mode.Bypass)); + BindTextBox(HandleRuleRichTextBox, s => true, s => _mode.Handle = s.GetLines().ToList(), string.Join(Constants.EOF, _mode.Handle)); } - #region Model - - public IEnumerable Rules => RuleRichTextBox.Lines; - - private void RuleAdd(string value) + private void InitBindings() { - RuleRichTextBox.AppendText($"{value}\n"); + DNSTextBox.DataBindings.Add(new Binding("Enabled", HandleDNSCheckBox, "Checked", true)); + HandleProcDNSCheckBox.DataBindings.Add(new Binding("Enabled", HandleDNSCheckBox, "Checked", true)); + ProxyDNSCheckBox.DataBindings.Add(new Binding("Enabled", HandleDNSCheckBox, "Checked", true)); + ICMPDelayTextBox.DataBindings.Add(new Binding("Enabled", HandleICMPCheckBox, "Checked", true)); } - private void RuleAddRange(IEnumerable value) - { - foreach (string s in value) - { - RuleAdd(s); - } - } - - #endregion - public void ModeForm_Load(object sender, EventArgs e) { - if (_mode != null) + if (!IsCreateMode) { Text = "Edit Process Mode"; RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged; - RemarkTextBox.Text = _mode.Remark; - FilenameTextBox.Text = _mode.RelativePath; - RuleAddRange(_mode.Content); + RemarkTextBox.Text = _mode.i18NRemark; + FilenameTextBox.Text = ModeService.Instance.GetRelativePath(_mode.FullName); } + if (!_mode.FullName.EndsWith(".json")) + ControlButton.Enabled = false; + + BypassRuleRichTextBox.Text = string.Join(Constants.EOF, _mode.Bypass); + HandleRuleRichTextBox.Text = string.Join(Constants.EOF, _mode.Handle); i18N.TranslateForm(this); } private void SelectButton_Click(object sender, EventArgs e) { - var dialog = new CommonOpenFileDialog + RichTextBox ruleRichTextBox; + if (sender == HandleSelectButton) + ruleRichTextBox = HandleRuleRichTextBox; + else if (sender == BypassSelectButton) + ruleRichTextBox = BypassRuleRichTextBox; + else { - IsFolderPicker = true, - Multiselect = true, - Title = i18N.Translate("Select a folder"), - AddToMostRecentlyUsedList = false, - EnsurePathExists = true, - NavigateToShortcut = true - }; - - if (dialog.ShowDialog(Handle) == CommonFileDialogResult.Ok) - { - foreach (string p in dialog.FileNames) - { - string path = p; - if (!path.EndsWith(@"\")) - path += @"\"; - - RuleAdd($"^{path.ToRegexString()}"); - } + throw new InvalidOperationException(); } + + var dialog = new FolderBrowserDialog(); + + if (dialog.ShowDialog() == DialogResult.OK) + { + var path = dialog.SelectedPath; + if (!path.EndsWith(@"\")) + path += @"\"; + + AppendText(ruleRichTextBox, $"^{path.ToRegexString()}"); + } + } + + private static void AppendText(Control ruleTextBox, string value) + { + if (ruleTextBox.Text.Any()) + ruleTextBox.Text = ruleTextBox.Text.Trim() + Constants.EOF + value; + else + ruleTextBox.Text = value; } public void ControlButton_Click(object sender, EventArgs e) { - if (!RuleRichTextBox.Lines.Any()) - { - MessageBoxX.Show(i18N.Translate("Unable to add empty rule")); - return; - } - if (string.IsNullOrWhiteSpace(RemarkTextBox.Text)) { MessageBoxX.Show(i18N.Translate("Please enter a mode remark")); return; } - if (string.IsNullOrWhiteSpace(FilenameTextBox.Text)) - { - MessageBoxX.Show(i18N.Translate("Please enter a mode filename")); - return; - } + SaveBinds(); - if (_mode != null) - { - _mode.Remark = RemarkTextBox.Text; - _mode.Content.Clear(); - _mode.Content.AddRange(RuleRichTextBox.Lines); - - _mode.WriteFile(); - MessageBoxX.Show(i18N.Translate("Mode updated successfully")); - } - else + if (IsCreateMode) { var relativePath = FilenameTextBox.Text; - var fullName = ModeHelper.GetFullPath(relativePath); + var fullName = ModeService.Instance.GetFullPath(relativePath); if (File.Exists(fullName)) { MessageBoxX.Show(i18N.Translate("File already exists.\n Please Change the filename")); return; } - var mode = new Mode(fullName) - { - Type = ModeType.Process, - Remark = RemarkTextBox.Text - }; + _mode.FullName = fullName; - mode.Content.AddRange(RuleRichTextBox.Lines); - - mode.WriteFile(); + ModeService.Instance.Add(_mode); MessageBoxX.Show(i18N.Translate("Mode added successfully")); } + else + { + _mode.WriteFile(); + MessageBoxX.Show(i18N.Translate("Mode updated successfully")); + } Close(); } private void RemarkTextBox_TextChanged(object? sender, EventArgs? e) { + if (!IsHandleCreated) + return; + BeginInvoke(new Action(() => { FilenameTextBox.Text = FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text); @@ -158,24 +169,26 @@ namespace Netch.Forms.ModeForms private void ScanButton_Click(object sender, EventArgs e) { - var dialog = new CommonOpenFileDialog + RichTextBox ruleRichTextBox; + if (sender == HandleScanButton) + ruleRichTextBox = HandleRuleRichTextBox; + else if (sender == BypassScanButton) + ruleRichTextBox = BypassRuleRichTextBox; + else { - IsFolderPicker = true, - Multiselect = false, - Title = i18N.Translate("Select a folder"), - AddToMostRecentlyUsedList = false, - EnsurePathExists = true, - NavigateToShortcut = true - }; + throw new InvalidOperationException(); + } - if (dialog.ShowDialog(Handle) == CommonFileDialogResult.Ok) + var dialog = new FolderBrowserDialog(); + + if (dialog.ShowDialog() == DialogResult.OK) { - var path = dialog.FileName; + var path = dialog.SelectedPath; var list = new List(); const uint maxCount = 50; try { - ScanDirectory(path, list); + ScanDirectory(path, list, maxCount); } catch { @@ -185,13 +198,13 @@ namespace Netch.Forms.ModeForms return; } - RuleAddRange(list); + AppendText(ruleRichTextBox, string.Join(Constants.EOF, list)); } } private void ScanDirectory(string directory, List list, uint maxCount = 30) { - foreach (string dir in Directory.GetDirectories(directory)) + foreach (var dir in Directory.GetDirectories(directory)) ScanDirectory(dir, list, maxCount); list.AddRange( @@ -203,7 +216,7 @@ namespace Netch.Forms.ModeForms private void ValidationButton_Click(object sender, EventArgs e) { - if (!NFController.CheckRules(Rules, out var results)) + if (!NFController.CheckRules(_mode.Bypass, out var results)) MessageBoxX.Show(NFController.GenerateInvalidRulesMessage(results), LogLevel.WARNING); else MessageBoxX.Show("Fine"); diff --git a/Netch/Forms/ModeForms/ProcessForm.resx b/Netch/Forms/ModeForms/ProcessForm.resx index 1af7de15..9462b705 100644 --- a/Netch/Forms/ModeForms/ProcessForm.resx +++ b/Netch/Forms/ModeForms/ProcessForm.resx @@ -1,64 +1,4 @@ - - - + @@ -112,9 +52,9 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/Netch/Forms/ModeForms/RouteForm.Designer.cs b/Netch/Forms/ModeForms/RouteForm.Designer.cs index 99530b7f..7fba1ca2 100644 --- a/Netch/Forms/ModeForms/RouteForm.Designer.cs +++ b/Netch/Forms/ModeForms/RouteForm.Designer.cs @@ -32,166 +32,349 @@ namespace Netch.Forms.ModeForms /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox(); - this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.HandleTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.HandleLabel = new System.Windows.Forms.Label(); + this.HandleContentTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.HandleRuleRichTextBox = new System.Windows.Forms.RichTextBox(); + this.BypassTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.BypassLabel = new System.Windows.Forms.Label(); + this.BypassContentTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.BypassRuleRichTextBox = new System.Windows.Forms.RichTextBox(); + this.HandleDNSCheckBox = new Netch.Forms.SyncGlobalCheckBox(); + this.DNSLabel = new System.Windows.Forms.Label(); + this.DNSTextBox = new System.Windows.Forms.TextBox(); + this.UseCustomDNSCheckBox = new System.Windows.Forms.CheckBox(); + this.RuleTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.OptionsGroupBox = new System.Windows.Forms.GroupBox(); + this.RemarkLabel = new System.Windows.Forms.Label(); + this.RemarkTextBox = new System.Windows.Forms.TextBox(); this.FilenameLabel = new System.Windows.Forms.Label(); this.FilenameTextBox = new System.Windows.Forms.TextBox(); - this.ActionLabel = new System.Windows.Forms.Label(); - this.RemarkTextBox = new System.Windows.Forms.TextBox(); - this.RemarkLabel = new System.Windows.Forms.Label(); - this.containerControl1 = new System.Windows.Forms.ContainerControl(); - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); - this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ControlButton = new System.Windows.Forms.Button(); + this.NamePanel = new System.Windows.Forms.Panel(); + this.ConfigurationLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox(); + this.HandleTableLayoutPanel.SuspendLayout(); + this.HandleContentTableLayoutPanel.SuspendLayout(); + this.BypassTableLayoutPanel.SuspendLayout(); + this.BypassContentTableLayoutPanel.SuspendLayout(); + this.RuleTableLayoutPanel.SuspendLayout(); + this.OptionsGroupBox.SuspendLayout(); + this.NamePanel.SuspendLayout(); + this.ConfigurationLayoutPanel.SuspendLayout(); this.ConfigurationGroupBox.SuspendLayout(); - this.containerControl1.SuspendLayout(); - this.contextMenuStrip.SuspendLayout(); this.SuspendLayout(); // - // ConfigurationGroupBox + // HandleTableLayoutPanel // - this.ConfigurationGroupBox.Controls.Add(this.comboBox1); - this.ConfigurationGroupBox.Controls.Add(this.FilenameLabel); - this.ConfigurationGroupBox.Controls.Add(this.FilenameTextBox); - this.ConfigurationGroupBox.Controls.Add(this.ActionLabel); - this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox); - this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel); - this.ConfigurationGroupBox.Controls.Add(this.containerControl1); - this.ConfigurationGroupBox.Location = new System.Drawing.Point(8, 12); - this.ConfigurationGroupBox.Name = "ConfigurationGroupBox"; - this.ConfigurationGroupBox.Size = new System.Drawing.Size(340, 355); - this.ConfigurationGroupBox.TabIndex = 2; - this.ConfigurationGroupBox.TabStop = false; - this.ConfigurationGroupBox.Text = "Configuration"; + this.HandleTableLayoutPanel.ColumnCount = 1; + this.HandleTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.HandleTableLayoutPanel.Controls.Add(this.HandleLabel, 0, 0); + this.HandleTableLayoutPanel.Controls.Add(this.HandleContentTableLayoutPanel, 0, 1); + this.HandleTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.HandleTableLayoutPanel.Location = new System.Drawing.Point(3, 3); + this.HandleTableLayoutPanel.Name = "HandleTableLayoutPanel"; + this.HandleTableLayoutPanel.RowCount = 2; + this.HandleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.HandleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.HandleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.HandleTableLayoutPanel.Size = new System.Drawing.Size(455, 424); + this.HandleTableLayoutPanel.TabIndex = 1; // - // comboBox1 + // HandleLabel // - this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBox1.FormattingEnabled = true; - this.comboBox1.Location = new System.Drawing.Point(84, 49); - this.comboBox1.Name = "comboBox1"; - this.comboBox1.Size = new System.Drawing.Size(138, 25); - this.comboBox1.TabIndex = 11; + this.HandleLabel.AutoSize = true; + this.HandleLabel.Location = new System.Drawing.Point(3, 0); + this.HandleLabel.Name = "HandleLabel"; + this.HandleLabel.Size = new System.Drawing.Size(81, 17); + this.HandleLabel.TabIndex = 0; + this.HandleLabel.Text = "Handle rules"; // - // FilenameLabel + // HandleContentTableLayoutPanel // - this.FilenameLabel.AutoSize = true; - this.FilenameLabel.Location = new System.Drawing.Point(12, 79); - this.FilenameLabel.Name = "FilenameLabel"; - this.FilenameLabel.Size = new System.Drawing.Size(59, 17); - this.FilenameLabel.TabIndex = 6; - this.FilenameLabel.Text = "Filename"; + this.HandleContentTableLayoutPanel.ColumnCount = 1; + this.HandleContentTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.HandleContentTableLayoutPanel.Controls.Add(this.HandleRuleRichTextBox, 0, 0); + this.HandleContentTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.HandleContentTableLayoutPanel.Location = new System.Drawing.Point(3, 20); + this.HandleContentTableLayoutPanel.Name = "HandleContentTableLayoutPanel"; + this.HandleContentTableLayoutPanel.RowCount = 1; + this.HandleContentTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.HandleContentTableLayoutPanel.Size = new System.Drawing.Size(449, 401); + this.HandleContentTableLayoutPanel.TabIndex = 1; // - // FilenameTextBox + // HandleRuleRichTextBox // - this.FilenameTextBox.Location = new System.Drawing.Point(84, 76); - this.FilenameTextBox.Name = "FilenameTextBox"; - this.FilenameTextBox.ReadOnly = true; - this.FilenameTextBox.Size = new System.Drawing.Size(250, 23); - this.FilenameTextBox.TabIndex = 5; + this.HandleRuleRichTextBox.DetectUrls = false; + this.HandleRuleRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.HandleRuleRichTextBox.Location = new System.Drawing.Point(3, 3); + this.HandleRuleRichTextBox.Name = "HandleRuleRichTextBox"; + this.HandleRuleRichTextBox.Size = new System.Drawing.Size(443, 395); + this.HandleRuleRichTextBox.TabIndex = 0; + this.HandleRuleRichTextBox.Text = ""; + this.HandleRuleRichTextBox.WordWrap = false; // - // ActionLabel + // BypassTableLayoutPanel // - this.ActionLabel.AutoSize = true; - this.ActionLabel.Location = new System.Drawing.Point(12, 52); - this.ActionLabel.Name = "ActionLabel"; - this.ActionLabel.Size = new System.Drawing.Size(44, 17); - this.ActionLabel.TabIndex = 0; - this.ActionLabel.Text = "Action"; + this.BypassTableLayoutPanel.ColumnCount = 1; + this.BypassTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.BypassTableLayoutPanel.Controls.Add(this.BypassLabel, 0, 0); + this.BypassTableLayoutPanel.Controls.Add(this.BypassContentTableLayoutPanel, 0, 1); + this.BypassTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.BypassTableLayoutPanel.Location = new System.Drawing.Point(464, 3); + this.BypassTableLayoutPanel.Name = "BypassTableLayoutPanel"; + this.BypassTableLayoutPanel.RowCount = 2; + this.BypassTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.BypassTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.BypassTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.BypassTableLayoutPanel.Size = new System.Drawing.Size(455, 424); + this.BypassTableLayoutPanel.TabIndex = 2; // - // RemarkTextBox + // BypassLabel // - this.RemarkTextBox.Location = new System.Drawing.Point(84, 22); - this.RemarkTextBox.Name = "RemarkTextBox"; - this.RemarkTextBox.Size = new System.Drawing.Size(250, 23); - this.RemarkTextBox.TabIndex = 1; - this.RemarkTextBox.TextChanged += new System.EventHandler(this.RemarkTextBox_TextChanged); + this.BypassLabel.AutoSize = true; + this.BypassLabel.Location = new System.Drawing.Point(3, 0); + this.BypassLabel.Name = "BypassLabel"; + this.BypassLabel.Size = new System.Drawing.Size(81, 17); + this.BypassLabel.TabIndex = 0; + this.BypassLabel.Text = "Bypass rules"; + // + // BypassContentTableLayoutPanel + // + this.BypassContentTableLayoutPanel.ColumnCount = 1; + this.BypassContentTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.BypassContentTableLayoutPanel.Controls.Add(this.BypassRuleRichTextBox, 0, 0); + this.BypassContentTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.BypassContentTableLayoutPanel.Location = new System.Drawing.Point(3, 20); + this.BypassContentTableLayoutPanel.Name = "BypassContentTableLayoutPanel"; + this.BypassContentTableLayoutPanel.RowCount = 1; + this.BypassContentTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.BypassContentTableLayoutPanel.Size = new System.Drawing.Size(449, 401); + this.BypassContentTableLayoutPanel.TabIndex = 1; + // + // BypassRuleRichTextBox + // + this.BypassRuleRichTextBox.DetectUrls = false; + this.BypassRuleRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.BypassRuleRichTextBox.Location = new System.Drawing.Point(3, 3); + this.BypassRuleRichTextBox.Name = "BypassRuleRichTextBox"; + this.BypassRuleRichTextBox.Size = new System.Drawing.Size(443, 395); + this.BypassRuleRichTextBox.TabIndex = 0; + this.BypassRuleRichTextBox.Text = ""; + this.BypassRuleRichTextBox.WordWrap = false; + // + // HandleDNSCheckBox + // + this.HandleDNSCheckBox.AutoCheck = false; + this.HandleDNSCheckBox.AutoSize = true; + this.HandleDNSCheckBox.BackColor = System.Drawing.Color.Yellow; + this.HandleDNSCheckBox.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point); + this.HandleDNSCheckBox.GlobalValue = false; + this.HandleDNSCheckBox.Location = new System.Drawing.Point(8, 24); + this.HandleDNSCheckBox.Name = "HandleDNSCheckBox"; + this.HandleDNSCheckBox.Size = new System.Drawing.Size(203, 21); + this.HandleDNSCheckBox.SyncGlobal = false; + this.HandleDNSCheckBox.TabIndex = 2; + this.HandleDNSCheckBox.Text = "Handle DNS (DNS hijacking)"; + this.HandleDNSCheckBox.ThreeState = true; + this.HandleDNSCheckBox.UseVisualStyleBackColor = true; + this.HandleDNSCheckBox.Value = false; + // + // DNSLabel + // + this.DNSLabel.AutoSize = true; + this.DNSLabel.Location = new System.Drawing.Point(176, 56); + this.DNSLabel.Name = "DNSLabel"; + this.DNSLabel.Size = new System.Drawing.Size(34, 17); + this.DNSLabel.TabIndex = 3; + this.DNSLabel.Text = "DNS"; + // + // DNSTextBox + // + this.DNSTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.UseCustomDNSCheckBox, "Checked", true)); + this.DNSTextBox.Location = new System.Drawing.Point(224, 56); + this.DNSTextBox.Name = "DNSTextBox"; + this.DNSTextBox.Size = new System.Drawing.Size(184, 23); + this.DNSTextBox.TabIndex = 4; + this.DNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // UseCustomDNSCheckBox + // + this.UseCustomDNSCheckBox.AutoSize = true; + this.UseCustomDNSCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.HandleDNSCheckBox, "Checked", true)); + this.UseCustomDNSCheckBox.Location = new System.Drawing.Point(8, 56); + this.UseCustomDNSCheckBox.Name = "UseCustomDNSCheckBox"; + this.UseCustomDNSCheckBox.Size = new System.Drawing.Size(125, 21); + this.UseCustomDNSCheckBox.TabIndex = 7; + this.UseCustomDNSCheckBox.Text = "Use custom DNS"; + this.UseCustomDNSCheckBox.ThreeState = true; + this.UseCustomDNSCheckBox.UseVisualStyleBackColor = true; + // + // RuleTableLayoutPanel + // + this.RuleTableLayoutPanel.ColumnCount = 2; + this.RuleTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.RuleTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.RuleTableLayoutPanel.Controls.Add(this.HandleTableLayoutPanel, 0, 0); + this.RuleTableLayoutPanel.Controls.Add(this.BypassTableLayoutPanel, 1, 0); + this.RuleTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.RuleTableLayoutPanel.Location = new System.Drawing.Point(3, 206); + this.RuleTableLayoutPanel.Name = "RuleTableLayoutPanel"; + this.RuleTableLayoutPanel.RowCount = 1; + this.RuleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.RuleTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 430F)); + this.RuleTableLayoutPanel.Size = new System.Drawing.Size(922, 430); + this.RuleTableLayoutPanel.TabIndex = 2; + // + // OptionsGroupBox + // + this.OptionsGroupBox.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.OptionsGroupBox.Controls.Add(this.HandleDNSCheckBox); + this.OptionsGroupBox.Controls.Add(this.UseCustomDNSCheckBox); + this.OptionsGroupBox.Controls.Add(this.DNSLabel); + this.OptionsGroupBox.Controls.Add(this.DNSTextBox); + this.OptionsGroupBox.Location = new System.Drawing.Point(15, 81); + this.OptionsGroupBox.Name = "OptionsGroupBox"; + this.OptionsGroupBox.Size = new System.Drawing.Size(898, 119); + this.OptionsGroupBox.TabIndex = 1; + this.OptionsGroupBox.TabStop = false; + this.OptionsGroupBox.Visible = false; // // RemarkLabel // this.RemarkLabel.AutoSize = true; - this.RemarkLabel.Location = new System.Drawing.Point(12, 25); + this.RemarkLabel.Location = new System.Drawing.Point(8, 8); this.RemarkLabel.Name = "RemarkLabel"; this.RemarkLabel.Size = new System.Drawing.Size(53, 17); this.RemarkLabel.TabIndex = 0; this.RemarkLabel.Text = "Remark"; // - // containerControl1 + // RemarkTextBox // - this.containerControl1.Controls.Add(this.richTextBox1); - this.containerControl1.Location = new System.Drawing.Point(6, 103); - this.containerControl1.Name = "containerControl1"; - this.containerControl1.Size = new System.Drawing.Size(328, 246); - this.containerControl1.TabIndex = 10; - this.containerControl1.Text = "containerControl1"; + this.RemarkTextBox.Location = new System.Drawing.Point(72, 8); + this.RemarkTextBox.Name = "RemarkTextBox"; + this.RemarkTextBox.Size = new System.Drawing.Size(341, 23); + this.RemarkTextBox.TabIndex = 1; // - // richTextBox1 + // FilenameLabel // - this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill; - this.richTextBox1.Location = new System.Drawing.Point(0, 0); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(328, 246); - this.richTextBox1.TabIndex = 0; - this.richTextBox1.Text = ""; + this.FilenameLabel.AutoSize = true; + this.FilenameLabel.Location = new System.Drawing.Point(8, 40); + this.FilenameLabel.Name = "FilenameLabel"; + this.FilenameLabel.Size = new System.Drawing.Size(59, 17); + this.FilenameLabel.TabIndex = 2; + this.FilenameLabel.Text = "Filename"; // - // contextMenuStrip + // FilenameTextBox // - this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.DeleteToolStripMenuItem}); - this.contextMenuStrip.Name = "contextMenuStrip"; - this.contextMenuStrip.Size = new System.Drawing.Size(114, 26); - // - // DeleteToolStripMenuItem - // - this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem"; - this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(113, 22); - this.DeleteToolStripMenuItem.Text = "Delete"; + this.FilenameTextBox.Location = new System.Drawing.Point(72, 40); + this.FilenameTextBox.Name = "FilenameTextBox"; + this.FilenameTextBox.ReadOnly = true; + this.FilenameTextBox.Size = new System.Drawing.Size(341, 23); + this.FilenameTextBox.TabIndex = 3; // // ControlButton // - this.ControlButton.Location = new System.Drawing.Point(273, 373); + this.ControlButton.Location = new System.Drawing.Point(424, 40); this.ControlButton.Name = "ControlButton"; this.ControlButton.Size = new System.Drawing.Size(75, 23); - this.ControlButton.TabIndex = 3; + this.ControlButton.TabIndex = 4; this.ControlButton.Text = "Save"; this.ControlButton.UseVisualStyleBackColor = true; this.ControlButton.Click += new System.EventHandler(this.ControlButton_Click); // - // Route + // NamePanel + // + this.NamePanel.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.NamePanel.Controls.Add(this.RemarkLabel); + this.NamePanel.Controls.Add(this.RemarkTextBox); + this.NamePanel.Controls.Add(this.FilenameLabel); + this.NamePanel.Controls.Add(this.FilenameTextBox); + this.NamePanel.Controls.Add(this.ControlButton); + this.NamePanel.Location = new System.Drawing.Point(208, 3); + this.NamePanel.Name = "NamePanel"; + this.NamePanel.Size = new System.Drawing.Size(512, 72); + this.NamePanel.TabIndex = 0; + // + // ConfigurationLayoutPanel + // + this.ConfigurationLayoutPanel.ColumnCount = 1; + this.ConfigurationLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.ConfigurationLayoutPanel.Controls.Add(this.NamePanel, 0, 0); + this.ConfigurationLayoutPanel.Controls.Add(this.OptionsGroupBox, 0, 1); + this.ConfigurationLayoutPanel.Controls.Add(this.RuleTableLayoutPanel, 0, 2); + this.ConfigurationLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.ConfigurationLayoutPanel.Location = new System.Drawing.Point(3, 19); + this.ConfigurationLayoutPanel.Name = "ConfigurationLayoutPanel"; + this.ConfigurationLayoutPanel.RowCount = 3; + this.ConfigurationLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.ConfigurationLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.ConfigurationLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.ConfigurationLayoutPanel.Size = new System.Drawing.Size(928, 639); + this.ConfigurationLayoutPanel.TabIndex = 0; + // + // ConfigurationGroupBox + // + this.ConfigurationGroupBox.Controls.Add(this.ConfigurationLayoutPanel); + this.ConfigurationGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.ConfigurationGroupBox.Location = new System.Drawing.Point(0, 0); + this.ConfigurationGroupBox.Name = "ConfigurationGroupBox"; + this.ConfigurationGroupBox.Size = new System.Drawing.Size(934, 661); + this.ConfigurationGroupBox.TabIndex = 1; + this.ConfigurationGroupBox.TabStop = false; + this.ConfigurationGroupBox.Text = "Configuration"; + // + // RouteForm // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(356, 419); + this.ClientSize = new System.Drawing.Size(934, 661); this.Controls.Add(this.ConfigurationGroupBox); - this.Controls.Add(this.ControlButton); + this.MinimumSize = new System.Drawing.Size(950, 700); this.Name = "RouteForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Create Route Table Rule"; this.Load += new System.EventHandler(this.Route_Load); + this.HandleTableLayoutPanel.ResumeLayout(false); + this.HandleTableLayoutPanel.PerformLayout(); + this.HandleContentTableLayoutPanel.ResumeLayout(false); + this.BypassTableLayoutPanel.ResumeLayout(false); + this.BypassTableLayoutPanel.PerformLayout(); + this.BypassContentTableLayoutPanel.ResumeLayout(false); + this.RuleTableLayoutPanel.ResumeLayout(false); + this.OptionsGroupBox.ResumeLayout(false); + this.OptionsGroupBox.PerformLayout(); + this.NamePanel.ResumeLayout(false); + this.NamePanel.PerformLayout(); + this.ConfigurationLayoutPanel.ResumeLayout(false); this.ConfigurationGroupBox.ResumeLayout(false); - this.ConfigurationGroupBox.PerformLayout(); - this.containerControl1.ResumeLayout(false); - this.contextMenuStrip.ResumeLayout(false); this.ResumeLayout(false); } - public System.Windows.Forms.GroupBox ConfigurationGroupBox; - private System.Windows.Forms.ContainerControl containerControl1; - private System.Windows.Forms.ContextMenuStrip contextMenuStrip; - public System.Windows.Forms.Button ControlButton; - private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem; - private System.Windows.Forms.Label FilenameLabel; - private System.Windows.Forms.TextBox FilenameTextBox; - private System.Windows.Forms.Label RemarkLabel; - private System.Windows.Forms.TextBox RemarkTextBox; - private System.Windows.Forms.RichTextBox richTextBox1; - #endregion - private System.Windows.Forms.ComboBox comboBox1; - private System.Windows.Forms.Label ActionLabel; + private System.Windows.Forms.TableLayoutPanel HandleTableLayoutPanel; + private System.Windows.Forms.Label HandleLabel; + private System.Windows.Forms.TableLayoutPanel HandleContentTableLayoutPanel; + private System.Windows.Forms.RichTextBox HandleRuleRichTextBox; + private System.Windows.Forms.TableLayoutPanel BypassTableLayoutPanel; + private System.Windows.Forms.Label BypassLabel; + private System.Windows.Forms.TableLayoutPanel BypassContentTableLayoutPanel; + private System.Windows.Forms.RichTextBox BypassRuleRichTextBox; + private SyncGlobalCheckBox HandleDNSCheckBox; + private System.Windows.Forms.Label DNSLabel; + private System.Windows.Forms.TextBox DNSTextBox; + private System.Windows.Forms.TableLayoutPanel RuleTableLayoutPanel; + private System.Windows.Forms.GroupBox OptionsGroupBox; + private System.Windows.Forms.Label RemarkLabel; + private System.Windows.Forms.TextBox RemarkTextBox; + private System.Windows.Forms.Label FilenameLabel; + private System.Windows.Forms.TextBox FilenameTextBox; + private System.Windows.Forms.Panel NamePanel; + private System.Windows.Forms.TableLayoutPanel ConfigurationLayoutPanel; + private System.Windows.Forms.CheckBox UseCustomDNSCheckBox; + private System.Windows.Forms.Button ControlButton; + private System.Windows.Forms.GroupBox ConfigurationGroupBox; } } \ No newline at end of file diff --git a/Netch/Forms/ModeForms/RouteForm.cs b/Netch/Forms/ModeForms/RouteForm.cs index 6134d490..fdc36398 100644 --- a/Netch/Forms/ModeForms/RouteForm.cs +++ b/Netch/Forms/ModeForms/RouteForm.cs @@ -1,47 +1,61 @@ -using Netch.Models; -using Netch.Properties; -using Netch.Utils; -using System; +using System; using System.IO; -using System.Windows.Forms; -using Netch.Enums; +using System.Linq; +using Netch.Models.Modes; +using Netch.Models.Modes.TunMode; +using Netch.Properties; +using Netch.Services; +using Netch.Utils; namespace Netch.Forms.ModeForms { - public partial class RouteForm : Form + public partial class RouteForm : BindingForm { - private readonly TagItem[] _items = - { new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") }; + private readonly bool IsCreateMode; - private readonly Mode? _mode; + private readonly TunMode _mode; public RouteForm(Mode? mode = null) { - if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs)) - throw new ArgumentOutOfRangeException(); - - _mode = mode; + switch (mode) + { + case null: + IsCreateMode = true; + _mode = new TunMode(); + break; + case TunMode tunMode: + IsCreateMode = false; + _mode = tunMode; + break; + default: + throw new ArgumentOutOfRangeException(); + } InitializeComponent(); Icon = Resources.icon; - comboBox1.DataSource = _items; - comboBox1.ValueMember = nameof(TagItem.Value); - comboBox1.DisplayMember = nameof(TagItem.Text); + + + BindTextBox(RemarkTextBox, _ => true, s => _mode.i18NRemark = s, _mode.i18NRemark); + // TODO Options Not implemented + + BindTextBox(BypassRuleRichTextBox, s => true, s => _mode.Bypass = s.GetLines().ToList(), string.Join(Constants.EOF, _mode.Bypass)); + BindTextBox(HandleRuleRichTextBox, s => true, s => _mode.Handle = s.GetLines().ToList(), string.Join(Constants.EOF, _mode.Handle)); } private void Route_Load(object sender, EventArgs e) { - if (_mode != null) + if (!IsCreateMode) { Text = "Edit Route Table Rule"; RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged; - RemarkTextBox.Text = _mode.Remark; - comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor - FilenameTextBox.Text = _mode.RelativePath; - richTextBox1.Lines = _mode.Content.ToArray(); + RemarkTextBox.Text = _mode.i18NRemark; + FilenameTextBox.Text = ModeService.Instance.GetRelativePath(_mode.FullName); } + if (!_mode.FullName.EndsWith(".json")) + ControlButton.Enabled = false; + i18N.TranslateForm(this); } @@ -53,50 +67,33 @@ namespace Netch.Forms.ModeForms return; } - if (string.IsNullOrWhiteSpace(FilenameTextBox.Text)) - { - MessageBoxX.Show(i18N.Translate("Please enter a mode filename")); - return; - } - - if (_mode != null) - { - _mode.Remark = RemarkTextBox.Text; - _mode.Content.Clear(); - _mode.Content.AddRange(richTextBox1.Lines); - _mode.Type = (ModeType)comboBox1.SelectedValue; - - _mode.WriteFile(); - MessageBoxX.Show(i18N.Translate("Mode updated successfully")); - } - else + if (IsCreateMode) { var relativePath = FilenameTextBox.Text; - var fullName = ModeHelper.GetFullPath(relativePath); + var fullName = ModeService.Instance.GetFullPath(relativePath); if (File.Exists(fullName)) { MessageBoxX.Show(i18N.Translate("File already exists.\n Please Change the filename")); return; } - var mode = new Mode(fullName) - { - Type = (ModeType)comboBox1.SelectedValue, - Remark = RemarkTextBox.Text - }; + _mode.FullName = fullName; - mode.Content.AddRange(richTextBox1.Lines); - - mode.WriteFile(); + ModeService.Instance.Add(_mode); MessageBoxX.Show(i18N.Translate("Mode added successfully")); } + else + { + _mode.WriteFile(); + MessageBoxX.Show(i18N.Translate("Mode updated successfully")); + } Close(); } private void RemarkTextBox_TextChanged(object? sender, EventArgs? e) { - BeginInvoke(new Action(() => { FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text); })); + FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text); } } } \ No newline at end of file diff --git a/Netch/Forms/SettingForm.Designer.cs b/Netch/Forms/SettingForm.Designer.cs index df414492..8e6c77c5 100644 --- a/Netch/Forms/SettingForm.Designer.cs +++ b/Netch/Forms/SettingForm.Designer.cs @@ -51,13 +51,16 @@ namespace Netch.Forms this.LanguageLabel = new System.Windows.Forms.Label(); this.LanguageComboBox = new System.Windows.Forms.ComboBox(); this.NFTabPage = new System.Windows.Forms.TabPage(); - this.ProcessFilterProtocolLabel = new System.Windows.Forms.Label(); - this.ProcessFilterProtocolComboBox = new System.Windows.Forms.ComboBox(); + this.FilterTCPCheckBox = new System.Windows.Forms.CheckBox(); + this.FilterUDPCheckBox = new System.Windows.Forms.CheckBox(); this.FilterICMPCheckBox = new System.Windows.Forms.CheckBox(); + this.DNSHijackLabel = new System.Windows.Forms.Label(); this.ICMPDelayLabel = new System.Windows.Forms.Label(); this.ICMPDelayTextBox = new System.Windows.Forms.TextBox(); - this.DNSHijackCheckBox = new System.Windows.Forms.CheckBox(); + this.FilterDNSCheckBox = new System.Windows.Forms.CheckBox(); this.DNSHijackHostTextBox = new System.Windows.Forms.TextBox(); + this.DNSProxyCheckBox = new System.Windows.Forms.CheckBox(); + this.HandleProcDNSCheckBox = new System.Windows.Forms.CheckBox(); this.ChildProcessHandleCheckBox = new System.Windows.Forms.CheckBox(); this.WinTUNTabPage = new System.Windows.Forms.TabPage(); this.WinTUNGroupBox = new System.Windows.Forms.GroupBox(); @@ -109,7 +112,6 @@ namespace Netch.Forms this.AioDNSListenPortTextBox = new System.Windows.Forms.TextBox(); this.ControlButton = new System.Windows.Forms.Button(); this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); - this.DNSHijackLabel = new System.Windows.Forms.Label(); this.TabControl.SuspendLayout(); this.GeneralTabPage.SuspendLayout(); this.PortGroupBox.SuspendLayout(); @@ -322,14 +324,16 @@ namespace Netch.Forms // NFTabPage // this.NFTabPage.BackColor = System.Drawing.SystemColors.ButtonFace; - this.NFTabPage.Controls.Add(this.ProcessFilterProtocolLabel); - this.NFTabPage.Controls.Add(this.ProcessFilterProtocolComboBox); + this.NFTabPage.Controls.Add(this.FilterTCPCheckBox); + this.NFTabPage.Controls.Add(this.FilterUDPCheckBox); this.NFTabPage.Controls.Add(this.FilterICMPCheckBox); this.NFTabPage.Controls.Add(this.DNSHijackLabel); this.NFTabPage.Controls.Add(this.ICMPDelayLabel); this.NFTabPage.Controls.Add(this.ICMPDelayTextBox); - this.NFTabPage.Controls.Add(this.DNSHijackCheckBox); + this.NFTabPage.Controls.Add(this.FilterDNSCheckBox); this.NFTabPage.Controls.Add(this.DNSHijackHostTextBox); + this.NFTabPage.Controls.Add(this.HandleProcDNSCheckBox); + this.NFTabPage.Controls.Add(this.DNSProxyCheckBox); this.NFTabPage.Controls.Add(this.ChildProcessHandleCheckBox); this.NFTabPage.Location = new System.Drawing.Point(4, 29); this.NFTabPage.Name = "NFTabPage"; @@ -338,79 +342,112 @@ namespace Netch.Forms this.NFTabPage.TabIndex = 1; this.NFTabPage.Text = "Process Mode"; // - // ProcessFilterProtocolLabel + // FilterTCPCheckBox // - this.ProcessFilterProtocolLabel.AutoSize = true; - this.ProcessFilterProtocolLabel.Location = new System.Drawing.Point(30, 20); - this.ProcessFilterProtocolLabel.Name = "ProcessFilterProtocolLabel"; - this.ProcessFilterProtocolLabel.Size = new System.Drawing.Size(89, 17); - this.ProcessFilterProtocolLabel.TabIndex = 0; - this.ProcessFilterProtocolLabel.Text = "Filter Protocol"; + this.FilterTCPCheckBox.AutoSize = true; + this.FilterTCPCheckBox.Location = new System.Drawing.Point(16, 16); + this.FilterTCPCheckBox.Name = "FilterTCPCheckBox"; + this.FilterTCPCheckBox.Size = new System.Drawing.Size(81, 21); + this.FilterTCPCheckBox.TabIndex = 1; + this.FilterTCPCheckBox.Text = "Handle TCP"; + this.FilterTCPCheckBox.UseVisualStyleBackColor = true; // - // ProcessFilterProtocolComboBox + // FilterUDPCheckBox // - this.ProcessFilterProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.ProcessFilterProtocolComboBox.FormattingEnabled = true; - this.ProcessFilterProtocolComboBox.Location = new System.Drawing.Point(237, 17); - this.ProcessFilterProtocolComboBox.Name = "ProcessFilterProtocolComboBox"; - this.ProcessFilterProtocolComboBox.Size = new System.Drawing.Size(98, 25); - this.ProcessFilterProtocolComboBox.TabIndex = 1; + this.FilterUDPCheckBox.AutoSize = true; + this.FilterUDPCheckBox.Location = new System.Drawing.Point(216, 16); + this.FilterUDPCheckBox.Name = "FilterUDPCheckBox"; + this.FilterUDPCheckBox.Size = new System.Drawing.Size(84, 21); + this.FilterUDPCheckBox.TabIndex = 2; + this.FilterUDPCheckBox.Text = "Handle UDP"; + this.FilterUDPCheckBox.UseVisualStyleBackColor = true; // // FilterICMPCheckBox // this.FilterICMPCheckBox.AutoSize = true; - this.FilterICMPCheckBox.Location = new System.Drawing.Point(15, 50); + this.FilterICMPCheckBox.Location = new System.Drawing.Point(16, 48); this.FilterICMPCheckBox.Name = "FilterICMPCheckBox"; this.FilterICMPCheckBox.Size = new System.Drawing.Size(90, 21); - this.FilterICMPCheckBox.TabIndex = 2; - this.FilterICMPCheckBox.Text = "Filter ICMP"; + this.FilterICMPCheckBox.TabIndex = 3; + this.FilterICMPCheckBox.Text = "Handle ICMP"; this.FilterICMPCheckBox.UseVisualStyleBackColor = true; // + // DNSHijackLabel + // + this.DNSHijackLabel.AutoSize = true; + this.DNSHijackLabel.Location = new System.Drawing.Point(48, 144); + this.DNSHijackLabel.Name = "DNSHijackLabel"; + this.DNSHijackLabel.Size = new System.Drawing.Size(34, 17); + this.DNSHijackLabel.TabIndex = 3; + this.DNSHijackLabel.Text = "DNS"; + // // ICMPDelayLabel // this.ICMPDelayLabel.AutoSize = true; - this.ICMPDelayLabel.Location = new System.Drawing.Point(65, 80); + this.ICMPDelayLabel.Location = new System.Drawing.Point(48, 80); this.ICMPDelayLabel.Name = "ICMPDelayLabel"; this.ICMPDelayLabel.Size = new System.Drawing.Size(100, 17); this.ICMPDelayLabel.TabIndex = 3; - this.ICMPDelayLabel.Text = "ICMP Delay(ms)"; + this.ICMPDelayLabel.Text = "ICMP delay(ms)"; // // ICMPDelayTextBox // this.ICMPDelayTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterICMPCheckBox, "Checked", true)); - this.ICMPDelayTextBox.Location = new System.Drawing.Point(237, 77); + this.ICMPDelayTextBox.Location = new System.Drawing.Point(216, 80); this.ICMPDelayTextBox.Name = "ICMPDelayTextBox"; this.ICMPDelayTextBox.Size = new System.Drawing.Size(98, 23); this.ICMPDelayTextBox.TabIndex = 4; this.ICMPDelayTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; // - // DNSHijackCheckBox + // FilterDNSCheckBox // - this.DNSHijackCheckBox.AutoSize = true; - this.DNSHijackCheckBox.Location = new System.Drawing.Point(15, 110); - this.DNSHijackCheckBox.Name = "DNSHijackCheckBox"; - this.DNSHijackCheckBox.Size = new System.Drawing.Size(92, 21); - this.DNSHijackCheckBox.TabIndex = 5; - this.DNSHijackCheckBox.Text = "DNS Hijack"; - this.DNSHijackCheckBox.UseVisualStyleBackColor = true; + this.FilterDNSCheckBox.AutoSize = true; + this.FilterDNSCheckBox.Location = new System.Drawing.Point(16, 112); + this.FilterDNSCheckBox.Name = "FilterDNSCheckBox"; + this.FilterDNSCheckBox.Size = new System.Drawing.Size(85, 21); + this.FilterDNSCheckBox.TabIndex = 5; + this.FilterDNSCheckBox.Text = "Handle DNS (DNS hijacking)"; + this.FilterDNSCheckBox.UseVisualStyleBackColor = true; // // DNSHijackHostTextBox // - this.DNSHijackHostTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.DNSHijackCheckBox, "Checked", true)); - this.DNSHijackHostTextBox.Location = new System.Drawing.Point(237, 138); + this.DNSHijackHostTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterDNSCheckBox, "Checked", true)); + this.DNSHijackHostTextBox.Location = new System.Drawing.Point(216, 144); this.DNSHijackHostTextBox.Name = "DNSHijackHostTextBox"; this.DNSHijackHostTextBox.Size = new System.Drawing.Size(191, 23); this.DNSHijackHostTextBox.TabIndex = 6; this.DNSHijackHostTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; // + // DNSProxyCheckBox + // + this.DNSProxyCheckBox.AutoSize = true; + this.DNSProxyCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterDNSCheckBox, "Checked", true)); + this.DNSProxyCheckBox.Location = new System.Drawing.Point(16, 208); + this.DNSProxyCheckBox.Name = "DNSProxyCheckBox"; + this.DNSProxyCheckBox.Size = new System.Drawing.Size(184, 21); + this.DNSProxyCheckBox.TabIndex = 8; + this.DNSProxyCheckBox.Text = "Handle DNS through proxy"; + this.DNSProxyCheckBox.UseVisualStyleBackColor = true; + // + // HandleProcDNSCheckBox + // + this.HandleProcDNSCheckBox.AutoSize = true; + this.HandleProcDNSCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterDNSCheckBox, "Checked", true)); + this.HandleProcDNSCheckBox.Location = new System.Drawing.Point(16, 176); + this.HandleProcDNSCheckBox.Name = "HandleProcDNSCheckBox"; + this.HandleProcDNSCheckBox.Size = new System.Drawing.Size(203, 21); + this.HandleProcDNSCheckBox.TabIndex = 7; + this.HandleProcDNSCheckBox.Text = "Handle handled process's DNS"; + this.HandleProcDNSCheckBox.UseVisualStyleBackColor = true; + // // ChildProcessHandleCheckBox // this.ChildProcessHandleCheckBox.AutoSize = true; - this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(15, 170); + this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(16, 240); this.ChildProcessHandleCheckBox.Name = "ChildProcessHandleCheckBox"; this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(150, 21); - this.ChildProcessHandleCheckBox.TabIndex = 7; - this.ChildProcessHandleCheckBox.Text = "Child Process Handle"; + this.ChildProcessHandleCheckBox.TabIndex = 9; + this.ChildProcessHandleCheckBox.Text = "Handle child process"; this.ChildProcessHandleCheckBox.UseVisualStyleBackColor = true; // // WinTUNTabPage @@ -519,7 +556,7 @@ namespace Netch.Forms this.UseCustomDNSCheckBox.Name = "UseCustomDNSCheckBox"; this.UseCustomDNSCheckBox.Size = new System.Drawing.Size(127, 21); this.UseCustomDNSCheckBox.TabIndex = 8; - this.UseCustomDNSCheckBox.Text = "Use Custom DNS"; + this.UseCustomDNSCheckBox.Text = "Use custom DNS"; this.UseCustomDNSCheckBox.UseVisualStyleBackColor = true; this.UseCustomDNSCheckBox.Click += new System.EventHandler(this.TUNTAPUseCustomDNSCheckBox_CheckedChanged); // @@ -743,7 +780,7 @@ namespace Netch.Forms // ExitWhenClosedCheckBox // this.ExitWhenClosedCheckBox.AutoSize = true; - this.ExitWhenClosedCheckBox.Location = new System.Drawing.Point(6, 6); + this.ExitWhenClosedCheckBox.Location = new System.Drawing.Point(16, 16); this.ExitWhenClosedCheckBox.Name = "ExitWhenClosedCheckBox"; this.ExitWhenClosedCheckBox.Size = new System.Drawing.Size(123, 21); this.ExitWhenClosedCheckBox.TabIndex = 0; @@ -754,7 +791,7 @@ namespace Netch.Forms // StopWhenExitedCheckBox // this.StopWhenExitedCheckBox.AutoSize = true; - this.StopWhenExitedCheckBox.Location = new System.Drawing.Point(200, 6); + this.StopWhenExitedCheckBox.Location = new System.Drawing.Point(224, 18); this.StopWhenExitedCheckBox.Name = "StopWhenExitedCheckBox"; this.StopWhenExitedCheckBox.Size = new System.Drawing.Size(127, 21); this.StopWhenExitedCheckBox.TabIndex = 1; @@ -765,7 +802,7 @@ namespace Netch.Forms // StartWhenOpenedCheckBox // this.StartWhenOpenedCheckBox.AutoSize = true; - this.StartWhenOpenedCheckBox.Location = new System.Drawing.Point(6, 28); + this.StartWhenOpenedCheckBox.Location = new System.Drawing.Point(16, 48); this.StartWhenOpenedCheckBox.Name = "StartWhenOpenedCheckBox"; this.StartWhenOpenedCheckBox.Size = new System.Drawing.Size(137, 21); this.StartWhenOpenedCheckBox.TabIndex = 2; @@ -776,7 +813,7 @@ namespace Netch.Forms // MinimizeWhenStartedCheckBox // this.MinimizeWhenStartedCheckBox.AutoSize = true; - this.MinimizeWhenStartedCheckBox.Location = new System.Drawing.Point(200, 28); + this.MinimizeWhenStartedCheckBox.Location = new System.Drawing.Point(224, 48); this.MinimizeWhenStartedCheckBox.Name = "MinimizeWhenStartedCheckBox"; this.MinimizeWhenStartedCheckBox.Size = new System.Drawing.Size(158, 21); this.MinimizeWhenStartedCheckBox.TabIndex = 3; @@ -786,7 +823,7 @@ namespace Netch.Forms // RunAtStartupCheckBox // this.RunAtStartupCheckBox.AutoSize = true; - this.RunAtStartupCheckBox.Location = new System.Drawing.Point(6, 50); + this.RunAtStartupCheckBox.Location = new System.Drawing.Point(16, 80); this.RunAtStartupCheckBox.Name = "RunAtStartupCheckBox"; this.RunAtStartupCheckBox.Size = new System.Drawing.Size(109, 21); this.RunAtStartupCheckBox.TabIndex = 4; @@ -796,7 +833,7 @@ namespace Netch.Forms // CheckUpdateWhenOpenedCheckBox // this.CheckUpdateWhenOpenedCheckBox.AutoSize = true; - this.CheckUpdateWhenOpenedCheckBox.Location = new System.Drawing.Point(200, 50); + this.CheckUpdateWhenOpenedCheckBox.Location = new System.Drawing.Point(224, 80); this.CheckUpdateWhenOpenedCheckBox.Name = "CheckUpdateWhenOpenedCheckBox"; this.CheckUpdateWhenOpenedCheckBox.Size = new System.Drawing.Size(190, 21); this.CheckUpdateWhenOpenedCheckBox.TabIndex = 5; @@ -807,7 +844,7 @@ namespace Netch.Forms // NoSupportDialogCheckBox // this.NoSupportDialogCheckBox.AutoSize = true; - this.NoSupportDialogCheckBox.Location = new System.Drawing.Point(6, 72); + this.NoSupportDialogCheckBox.Location = new System.Drawing.Point(16, 112); this.NoSupportDialogCheckBox.Name = "NoSupportDialogCheckBox"; this.NoSupportDialogCheckBox.Size = new System.Drawing.Size(174, 21); this.NoSupportDialogCheckBox.TabIndex = 6; @@ -817,7 +854,7 @@ namespace Netch.Forms // CheckBetaUpdateCheckBox // this.CheckBetaUpdateCheckBox.AutoSize = true; - this.CheckBetaUpdateCheckBox.Location = new System.Drawing.Point(200, 72); + this.CheckBetaUpdateCheckBox.Location = new System.Drawing.Point(224, 112); this.CheckBetaUpdateCheckBox.Name = "CheckBetaUpdateCheckBox"; this.CheckBetaUpdateCheckBox.Size = new System.Drawing.Size(137, 21); this.CheckBetaUpdateCheckBox.TabIndex = 7; @@ -828,7 +865,7 @@ namespace Netch.Forms // UpdateServersWhenOpenedCheckBox // this.UpdateServersWhenOpenedCheckBox.AutoSize = true; - this.UpdateServersWhenOpenedCheckBox.Location = new System.Drawing.Point(200, 94); + this.UpdateServersWhenOpenedCheckBox.Location = new System.Drawing.Point(224, 144); this.UpdateServersWhenOpenedCheckBox.Name = "UpdateServersWhenOpenedCheckBox"; this.UpdateServersWhenOpenedCheckBox.Size = new System.Drawing.Size(200, 21); this.UpdateServersWhenOpenedCheckBox.TabIndex = 8; @@ -927,15 +964,6 @@ namespace Netch.Forms this.flowLayoutPanel1.Size = new System.Drawing.Size(480, 400); this.flowLayoutPanel1.TabIndex = 0; // - // DNSHijackLabel - // - this.DNSHijackLabel.AutoSize = true; - this.DNSHijackLabel.Location = new System.Drawing.Point(65, 140); - this.DNSHijackLabel.Name = "DNSHijackLabel"; - this.DNSHijackLabel.Size = new System.Drawing.Size(34, 17); - this.DNSHijackLabel.TabIndex = 3; - this.DNSHijackLabel.Text = "DNS"; - // // SettingForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -999,7 +1027,7 @@ namespace Netch.Forms private System.Windows.Forms.Label TUNTAPAddressLabel; private System.Windows.Forms.TextBox TUNTAPAddressTextBox; private System.Windows.Forms.Button GlobalBypassIPsButton; - private System.Windows.Forms.CheckBox DNSHijackCheckBox; + private System.Windows.Forms.CheckBox FilterDNSCheckBox; private System.Windows.Forms.Button ControlButton; private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; private System.Windows.Forms.TabPage OtherTabPage; @@ -1047,13 +1075,15 @@ namespace Netch.Forms private System.Windows.Forms.Label ServerPingTypeLabel; private System.Windows.Forms.RadioButton TCPingRadioBtn; private System.Windows.Forms.RadioButton ICMPingRadioBtn; - private System.Windows.Forms.ComboBox ProcessFilterProtocolComboBox; - private System.Windows.Forms.Label ProcessFilterProtocolLabel; private System.Windows.Forms.CheckBox FilterICMPCheckBox; private System.Windows.Forms.CheckBox ChildProcessHandleCheckBox; private System.Windows.Forms.TextBox ICMPDelayTextBox; private System.Windows.Forms.Label ICMPDelayLabel; private System.Windows.Forms.CheckBox NoSupportDialogCheckBox; private System.Windows.Forms.Label DNSHijackLabel; + private System.Windows.Forms.CheckBox HandleProcDNSCheckBox; + private System.Windows.Forms.CheckBox FilterTCPCheckBox; + private System.Windows.Forms.CheckBox FilterUDPCheckBox; + private System.Windows.Forms.CheckBox DNSProxyCheckBox; } } \ No newline at end of file diff --git a/Netch/Forms/SettingForm.cs b/Netch/Forms/SettingForm.cs index 8704acbb..6fdb3150 100644 --- a/Netch/Forms/SettingForm.cs +++ b/Netch/Forms/SettingForm.cs @@ -1,23 +1,17 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Windows.Forms; -using Netch.Models; using Netch.Properties; using Netch.Utils; using Serilog; namespace Netch.Forms { - public partial class SettingForm : Form + public partial class SettingForm : BindingForm { - private readonly Dictionary> _checkActions = new(); - - private readonly Dictionary> _saveActions = new(); - public SettingForm() { InitializeComponent(); @@ -89,22 +83,25 @@ namespace Netch.Forms #region Process Mode - BindListComboBox(ProcessFilterProtocolComboBox, - s => Global.Settings.Redirector.FilterProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false), - Enum.GetNames(typeof(PortType)), - Global.Settings.Redirector.FilterProtocol.ToString()); + BindCheckBox(FilterTCPCheckBox, b => Global.Settings.Redirector.FilterTCP = b, Global.Settings.Redirector.FilterTCP); + + BindCheckBox(FilterUDPCheckBox, b => Global.Settings.Redirector.FilterUDP = b, Global.Settings.Redirector.FilterUDP); BindCheckBox(FilterICMPCheckBox, b => Global.Settings.Redirector.FilterICMP = b, Global.Settings.Redirector.FilterICMP); BindTextBox(ICMPDelayTextBox, s => true, s => Global.Settings.Redirector.ICMPDelay = s, Global.Settings.Redirector.ICMPDelay); - BindCheckBox(DNSHijackCheckBox, b => Global.Settings.Redirector.DNSHijack = b, Global.Settings.Redirector.DNSHijack); + BindCheckBox(FilterDNSCheckBox, b => Global.Settings.Redirector.FilterDNS = b, Global.Settings.Redirector.FilterDNS); - BindTextBox(DNSHijackHostTextBox, s => true, s => Global.Settings.Redirector.DNSHijackHost = s, Global.Settings.Redirector.DNSHijackHost); + BindTextBox(DNSHijackHostTextBox, s => true, s => Global.Settings.Redirector.DNSHost = s, Global.Settings.Redirector.DNSHost); BindCheckBox(ChildProcessHandleCheckBox, - s => Global.Settings.Redirector.ChildProcessHandle = s, - Global.Settings.Redirector.ChildProcessHandle); + s => Global.Settings.Redirector.FilterParent = s, + Global.Settings.Redirector.FilterParent); + + BindCheckBox(DNSProxyCheckBox, b => Global.Settings.Redirector.DNSProxy = b, Global.Settings.Redirector.DNSProxy); + + BindCheckBox(HandleProcDNSCheckBox, b => Global.Settings.Redirector.HandleOnlyDNS = b, Global.Settings.Redirector.HandleOnlyDNS); #endregion @@ -237,7 +234,7 @@ namespace Netch.Forms #region Check - var checkNotPassControl = _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)).Select(pair => pair.Key).ToList(); + var checkNotPassControl = GetCheckFailedControls(); foreach (Control control in checkNotPassControl) Utils.Utils.ChangeControlForeColor(control, Color.Red); @@ -248,8 +245,7 @@ namespace Netch.Forms #region Save - foreach (var pair in _saveActions) - pair.Value.Invoke(pair.Key); + SaveBinds(); #endregion @@ -259,71 +255,5 @@ namespace Netch.Forms MessageBoxX.Show(i18N.Translate("Saved")); Close(); } - - #region BindUtils - - private void BindTextBox(TextBox control, Func check, Action save, object value) - { - BindTextBox(control, check, save, value); - } - - private void BindTextBox(TextBox control, Func check, Action save, object value) - { - control.Text = value.ToString(); - _checkActions.Add(control, - s => - { - try - { - return check.Invoke((T)Convert.ChangeType(s, typeof(T))); - } - catch - { - return false; - } - }); - - _saveActions.Add(control, c => save.Invoke((T)Convert.ChangeType(((TextBox)c).Text, typeof(T)))); - } - - private void BindCheckBox(CheckBox control, Action save, bool value) - { - control.Checked = value; - _saveActions.Add(control, c => save.Invoke(((CheckBox)c).Checked)); - } - - private void BindRadioBox(RadioButton control, Action save, bool value) - { - control.Checked = value; - _saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked)); - } - - private void BindListComboBox(ComboBox comboBox, Action save, IEnumerable values, T value) where T : notnull - { - if (comboBox.DropDownStyle != ComboBoxStyle.DropDownList) - throw new ArgumentOutOfRangeException(); - - var tagItems = values.Select(o => new TagItem(o, o.ToString()!)).ToArray(); - comboBox.Items.AddRange(tagItems.Cast().ToArray()); - - comboBox.ValueMember = nameof(TagItem.Value); - comboBox.DisplayMember = nameof(TagItem.Text); - - _saveActions.Add(comboBox, c => save.Invoke(((TagItem)((ComboBox)c).SelectedItem).Value)); - Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); }; - } - - private void BindComboBox(ComboBox control, Func check, Action save, string value, object[]? values = null) - { - if (values != null) - control.Items.AddRange(values); - - _saveActions.Add(control, c => save.Invoke(((ComboBox)c).Text)); - _checkActions.Add(control, check.Invoke); - - Load += (_, _) => { control.Text = value; }; - } - - #endregion } } \ No newline at end of file diff --git a/Netch/Forms/SyncGlobalCheckBox.cs b/Netch/Forms/SyncGlobalCheckBox.cs new file mode 100644 index 00000000..6205117c --- /dev/null +++ b/Netch/Forms/SyncGlobalCheckBox.cs @@ -0,0 +1,92 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace Netch.Forms +{ + public class SyncGlobalCheckBox : CheckBox + { + public SyncGlobalCheckBox() + { + AutoCheck = false; + OnSyncGlobalChanged(); + } + + private bool _syncGlobal; + + private bool _globalValue; + + public bool SyncGlobal + { + get => _syncGlobal; + set + { + if (value == _syncGlobal) + return; + + _syncGlobal = value; + + OnSyncGlobalChanged(); + } + } + + public bool GlobalValue + { + get => _globalValue; + set + { + if (value == _globalValue) + return; + + _globalValue = value; + + if (SyncGlobal) + Checked = value; + } + } + + protected override void OnClick(EventArgs e) + { + if (Checked == GlobalValue) + { + SyncGlobal = !SyncGlobal; + if (SyncGlobal) + return; + } + + Checked = !Checked; + base.OnClick(e); + } + + public bool? Value + { + get => _syncGlobal ? null : Checked; + set + { + if (value == null) + { + SyncGlobal = true; + } + else + { + SyncGlobal = false; + Checked = (bool)value; + } + } + } + + private void OnSyncGlobalChanged() + { + if (_syncGlobal) + { + Font = new Font(Font, FontStyle.Regular); + BackColor = SystemColors.Control; + } + else + { + Font = new Font(Font, FontStyle.Bold | FontStyle.Italic); + BackColor = Color.Yellow; + } + } + } +} \ No newline at end of file diff --git a/Netch/Global.cs b/Netch/Global.cs index a3b1b1b1..817b5fa7 100644 --- a/Netch/Global.cs +++ b/Netch/Global.cs @@ -6,6 +6,7 @@ using System.Text.Json.Serialization; using System.Windows.Forms; using Netch.Forms; using Netch.Models; +using Netch.Models.Modes; namespace Netch { diff --git a/Netch/Interfaces/IModeController.cs b/Netch/Interfaces/IModeController.cs index 3ceedf8b..9da824b8 100644 --- a/Netch/Interfaces/IModeController.cs +++ b/Netch/Interfaces/IModeController.cs @@ -1,11 +1,13 @@ using System.Threading.Tasks; -using Netch.Models; +using Netch.Models.Modes; using Netch.Servers; namespace Netch.Interfaces { public interface IModeController : IController { + public ModeFeature Features { get; } + public Task StartAsync(Socks5Server server, Mode mode); } } \ No newline at end of file diff --git a/Netch/Interops/Redirector.cs b/Netch/Interops/Redirector.cs index 6c66c391..a77d2165 100644 --- a/Netch/Interops/Redirector.cs +++ b/Netch/Interops/Redirector.cs @@ -33,6 +33,12 @@ namespace Netch.Interops AIO_BYPNAME } + public static bool Dial(NameList name, bool value) + { + Log.Verbose($"[Redirector] Dial {name}: {value}"); + return aio_dial(name, value.ToString().ToLower()); + } + public static bool Dial(NameList name, string value) { Log.Verbose($"[Redirector] Dial {name}: {value}"); diff --git a/Netch/JsonConverter/ModeConverterWithTypeDiscriminator.cs b/Netch/JsonConverter/ModeConverterWithTypeDiscriminator.cs new file mode 100644 index 00000000..905c937b --- /dev/null +++ b/Netch/JsonConverter/ModeConverterWithTypeDiscriminator.cs @@ -0,0 +1,44 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Netch.Models.Modes; +using Netch.Models.Modes.ProcessMode; +using Netch.Models.Modes.ShareMode; +using Netch.Models.Modes.TunMode; + +namespace Netch.JsonConverter +{ + public class ModeConverterWithTypeDiscriminator : JsonConverter + { + public override Mode? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var jsonElement = JsonSerializer.Deserialize(ref reader); + + var modeTypePropertyName = JsonNamingPolicy.CamelCase.ConvertName(nameof(Mode.Type)); + if (!jsonElement.TryGetProperty(modeTypePropertyName, out var modeTypeToken)) + throw new JsonException(); + + var modeTypeEnum = modeTypeToken.ValueKind switch + { + JsonValueKind.Number => (ModeType)modeTypeToken.GetInt32(), + JsonValueKind.String => Enum.Parse(modeTypeToken.GetString()!), + _ => throw new JsonException() + }; + + var modeType = modeTypeEnum switch + { + ModeType.ProcessMode => typeof(Redirector), + ModeType.TunMode => typeof(TunMode), + ModeType.ShareMode => typeof(ShareMode), + _ => throw new ArgumentOutOfRangeException() + }; + + return (Mode?)jsonElement.Deserialize(modeType, options); + } + + public override void Write(Utf8JsonWriter writer, Mode value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value, options); + } + } +} \ No newline at end of file diff --git a/Netch/JsonConverter/ServerConverterWithTypeDiscriminator.cs b/Netch/JsonConverter/ServerConverterWithTypeDiscriminator.cs index cb071358..83155dc4 100644 --- a/Netch/JsonConverter/ServerConverterWithTypeDiscriminator.cs +++ b/Netch/JsonConverter/ServerConverterWithTypeDiscriminator.cs @@ -8,8 +8,6 @@ namespace Netch.JsonConverter { public class ServerConverterWithTypeDiscriminator : JsonConverter { - public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Server); - public override Server Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var jsonElement = JsonSerializer.Deserialize(ref reader); diff --git a/Netch/Models/Mode.cs b/Netch/Models/Mode.cs deleted file mode 100644 index fbe2730a..00000000 --- a/Netch/Models/Mode.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Netch.Enums; -using Netch.Utils; - -namespace Netch.Models -{ - public class Mode - { - private List? _content; - - public Mode(string? fullName) - { - FullName = fullName; - if (FullName == null || !File.Exists(FullName)) - return; - - Load(); - } - - public string? FullName { get; } - - public List Content => _content ??= ReadContent(); - - public string Remark { get; set; } = ""; - - public ModeType Type { get; set; } = ModeType.Process; - - public string? RelativePath => FullName == null ? null : ModeHelper.GetRelativePath(FullName); - - private void Load() - { - if (FullName == null) - return; - - (Remark, Type) = ReadHead(FullName); - _content = null; - } - - public IEnumerable GetRules() - { - foreach (var s in Content) - { - if (string.IsNullOrWhiteSpace(s)) - continue; - - if (s.StartsWith("//")) - continue; - - const string include = "#include"; - if (s.StartsWith(include)) - { - var relativePath = new StringBuilder(s[include.Length..].Trim()); - relativePath.Replace("<", "").Replace(">", ""); - relativePath.Replace(".h", ".txt"); - - var mode = Global.Modes.FirstOrDefault(m => m.RelativePath?.Equals(relativePath.ToString()) ?? false) ?? - throw new MessageException($"{relativePath} file included in {Remark} not found"); - - if (mode == this) - throw new MessageException("Can't self-reference"); - - if (mode.Type != Type) - throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode"); - - if (mode.Content.Any(rule => rule.StartsWith(include))) - throw new Exception("Cannot reference mode that reference other mode"); - - foreach (var rule in mode.GetRules()) - yield return rule; - } - else - { - yield return s; - } - } - } - - private static (string, ModeType) ReadHead(string fileName) - { - var text = File.ReadLines(fileName).First(); - if (text.First() != '#') - throw new FormatException($"{fileName} head not found at Line 0"); - - var strings = text[1..].SplitTrimEntries(','); - - var remark = strings[0]; - var typeNumber = int.TryParse(strings.ElementAtOrDefault(1), out var type) ? type : 0; - - if (!Enum.GetValues(typeof(ModeType)).Cast().Contains(typeNumber)) - throw new NotSupportedException($"Not support mode \"{typeNumber}\"."); - - return (remark, (ModeType)typeNumber); - } - - private List ReadContent() - { - if (FullName == null || !File.Exists(FullName)) - return new List(); - - return File.ReadLines(FullName).Skip(1).ToList(); - } - - public void WriteFile() - { - var dir = Path.GetDirectoryName(FullName)!; - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - var content = $"# {Remark}, {(int)Type}{Constants.EOF}{string.Join(Constants.EOF, Content)}"; - // 写入到模式文件里 - File.WriteAllText(FullName!, content); - } - - public override string ToString() - { - return $"[{(int)Type + 1}] {i18N.Translate(Remark)}"; - } - } -} \ No newline at end of file diff --git a/Netch/Models/Modes/Mode.cs b/Netch/Models/Modes/Mode.cs new file mode 100644 index 00000000..9d40e265 --- /dev/null +++ b/Netch/Models/Modes/Mode.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Netch.Utils; + +namespace Netch.Models.Modes +{ + public abstract class Mode + { + [JsonPropertyOrder(int.MinValue)] + public abstract ModeType Type { get; } + + public Dictionary Remark { get; set; } = new(); + + [JsonIgnore] + // File FullName + // TODO maybe make it becomes mode dictionary key + public string FullName { get; set; } = null!; + + public override string ToString() => $"[{(int)Type + 1}] {i18NRemark}"; + + [JsonIgnore] + public string i18NRemark + { + // TODO i18N.Culture to support fallback + get => Remark.GetValueOrDefault(i18N.LangCode) ?? Remark.GetValueOrDefault("en") ?? ""; + set => Remark[i18N.LangCode] = value; + } + } +} \ No newline at end of file diff --git a/Netch/Enums/ModeFeature.cs b/Netch/Models/Modes/ModeFeature.cs similarity index 86% rename from Netch/Enums/ModeFeature.cs rename to Netch/Models/Modes/ModeFeature.cs index 01b82f9d..8e992582 100644 --- a/Netch/Enums/ModeFeature.cs +++ b/Netch/Models/Modes/ModeFeature.cs @@ -1,6 +1,6 @@ using System; -namespace Netch.Enums +namespace Netch.Models.Modes { [Flags] public enum ModeFeature diff --git a/Netch/Models/Modes/ModeType.cs b/Netch/Models/Modes/ModeType.cs new file mode 100644 index 00000000..14dfe8ad --- /dev/null +++ b/Netch/Models/Modes/ModeType.cs @@ -0,0 +1,20 @@ +namespace Netch.Models.Modes +{ + public enum ModeType + { + /// + /// 进程代理 + /// + ProcessMode, + + /// + /// 网络共享 + /// + ShareMode, + + /// + /// 网卡代理 + /// + TunMode + } +} diff --git a/Netch/Models/Modes/ProcessMode/ProcessMode.cs b/Netch/Models/Modes/ProcessMode/ProcessMode.cs new file mode 100644 index 00000000..77b5b73b --- /dev/null +++ b/Netch/Models/Modes/ProcessMode/ProcessMode.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace Netch.Models.Modes.ProcessMode +{ + public class Redirector : Mode + { + public override ModeType Type => ModeType.ProcessMode; + + #region Base + + public bool? FilterICMP { get; set; } + + public bool? FilterTCP { get; set; } + + public bool? FilterUDP { get; set; } + + public bool? FilterDNS { get; set; } + + public bool? FilterParent { get; set; } + + public int? ICMPDelay { get; set; } + + public bool? DNSProxy { get; set; } + + public bool? HandleOnlyDNS { get; set; } + + public string? DNSHost { get; set; } + + #endregion + + public bool FilterLoopback { get; set; } = false; + + public bool FilterIntranet { get; set; } = true; + + public List Bypass { get; set; } = new(); + + public List Handle { get; set; } = new(); + } +} \ No newline at end of file diff --git a/Netch/Models/Modes/ShareMode/ShareMode.cs b/Netch/Models/Modes/ShareMode/ShareMode.cs new file mode 100644 index 00000000..2cc71249 --- /dev/null +++ b/Netch/Models/Modes/ShareMode/ShareMode.cs @@ -0,0 +1,9 @@ +namespace Netch.Models.Modes.ShareMode +{ + public class ShareMode : Mode + { + public override ModeType Type => ModeType.ShareMode; + + public string Argument = "--preset uu"; + } +} \ No newline at end of file diff --git a/Netch/Models/Modes/TunMode/TunMode.cs b/Netch/Models/Modes/TunMode/TunMode.cs new file mode 100644 index 00000000..a6ce85a0 --- /dev/null +++ b/Netch/Models/Modes/TunMode/TunMode.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Netch.Models.Modes.TunMode +{ + public class TunMode : Mode + { + public override ModeType Type => ModeType.TunMode; + + public List Bypass { get; set; } = new(); + + public List Handle { get; set; } = new(); + } +} \ No newline at end of file diff --git a/Netch/Models/Profile.cs b/Netch/Models/Profile.cs index bf7d5ee1..aef8be23 100644 --- a/Netch/Models/Profile.cs +++ b/Netch/Models/Profile.cs @@ -1,4 +1,6 @@ -namespace Netch.Models +using Netch.Models.Modes; + +namespace Netch.Models { public class Profile { @@ -13,7 +15,7 @@ public Profile(Server server, Mode mode, string name, int index) { ServerRemark = server.Remark; - ModeRemark = mode.Remark; + ModeRemark = mode.i18NRemark; ProfileName = name; Index = index; } diff --git a/Netch/Models/Settings/AioDNSConfig.cs b/Netch/Models/Settings/AioDNSConfig.cs new file mode 100644 index 00000000..ff541c4c --- /dev/null +++ b/Netch/Models/Settings/AioDNSConfig.cs @@ -0,0 +1,11 @@ +namespace Netch.Models +{ + public class AioDNSConfig + { + public string ChinaDNS { get; set; } = $"tcp://{Constants.DefaultCNPrimaryDNS}"; + + public string OtherDNS { get; set; } = $"tcp://{Constants.DefaultPrimaryDNS}"; + + public ushort ListenPort { get; set; } = 253; + } +} \ No newline at end of file diff --git a/Netch/Models/Settings/KcpConfig.cs b/Netch/Models/Settings/KcpConfig.cs new file mode 100644 index 00000000..d7feb7a6 --- /dev/null +++ b/Netch/Models/Settings/KcpConfig.cs @@ -0,0 +1,19 @@ +namespace Netch.Models +{ + public class KcpConfig + { + public bool congestion { get; set; } = false; + + public int downlinkCapacity { get; set; } = 100; + + public int mtu { get; set; } = 1350; + + public int readBufferSize { get; set; } = 2; + + public int tti { get; set; } = 50; + + public int uplinkCapacity { get; set; } = 12; + + public int writeBufferSize { get; set; } = 2; + } +} \ No newline at end of file diff --git a/Netch/Models/Settings/RedirectorConfig.cs b/Netch/Models/Settings/RedirectorConfig.cs new file mode 100644 index 00000000..89ab063b --- /dev/null +++ b/Netch/Models/Settings/RedirectorConfig.cs @@ -0,0 +1,23 @@ +namespace Netch.Models +{ + public class RedirectorConfig + { + public bool FilterTCP { get; set; } = true; + + public bool FilterUDP { get; set; } = true; + + public bool FilterDNS { get; set; } = true; + + public bool FilterParent { get; set; } = false; + + public bool HandleOnlyDNS { get; set; } = true; + + public bool DNSProxy { get; set; } = true; + + public string DNSHost { get; set; } = Constants.DefaultPrimaryDNS; + + public int ICMPDelay { get; set; } = 10; + + public bool FilterICMP { get; set; } = false; + } +} \ No newline at end of file diff --git a/Netch/Models/Setting.cs b/Netch/Models/Settings/Setting.cs similarity index 63% rename from Netch/Models/Setting.cs rename to Netch/Models/Settings/Setting.cs index 68958e91..8aebe6c4 100644 --- a/Netch/Models/Setting.cs +++ b/Netch/Models/Settings/Setting.cs @@ -2,117 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json; -using Netch.Utils; namespace Netch.Models { - /// - /// TUN/TAP 适配器配置类 - /// - public class TUNConfig - { - /// - /// 地址 - /// - public string Address { get; set; } = "10.0.236.10"; - - /// - /// DNS - /// - public string HijackDNS { get; set; } = "tcp://1.1.1.1:53"; - - /// - /// 网关 - /// - public string Gateway { get; set; } = "10.0.236.1"; - - /// - /// 掩码 - /// - public string Netmask { get; set; } = "255.255.255.0"; - - /// - /// 模式 2 下是否代理 DNS - /// - public bool ProxyDNS { get; set; } = false; - - /// - /// 使用自定义 DNS 设置 - /// - public bool UseCustomDNS { get; set; } = false; - - /// - /// 全局绕过 IP 列表 - /// - public List BypassIPs { get; set; } = new(); - } - - public class KcpConfig - { - public bool congestion { get; set; } = false; - - public int downlinkCapacity { get; set; } = 100; - - public int mtu { get; set; } = 1350; - - public int readBufferSize { get; set; } = 2; - - public int tti { get; set; } = 50; - - public int uplinkCapacity { get; set; } = 12; - - public int writeBufferSize { get; set; } = 2; - } - - public class V2rayConfig - { - public bool AllowInsecure { get; set; } = false; - - public KcpConfig KcpConfig { get; set; } = new(); - - public bool UseMux { get; set; } = false; - - public bool V2rayNShareLink { get; set; } = true; - - public bool XrayCone { get; set; } = true; - } - - public class AioDNSConfig - { - public string ChinaDNS { get; set; } = "tcp://223.5.5.5:53"; - - public string OtherDNS { get; set; } = "tcp://1.1.1.1:53"; - - public ushort ListenPort { get; set; } = 253; - } - - public class RedirectorConfig - { - /// - /// 不代理TCP - /// - public PortType FilterProtocol { get; set; } = PortType.Both; - - /// - /// 是否开启DNS转发 - /// - public bool DNSHijack { get; set; } = true; - - /// - /// 转发DNS地址 - /// - public string DNSHijackHost { get; set; } = "1.1.1.1:53"; - - public int ICMPDelay { get; set; } = 0; - - public bool FilterICMP { get; set; } = false; - - /// - /// 是否代理子进程 - /// - public bool ChildProcessHandle { get; set; } = false; - } - /// /// 用于读取和写入的配置的类 /// diff --git a/Netch/Models/Settings/TUNConfig.cs b/Netch/Models/Settings/TUNConfig.cs new file mode 100644 index 00000000..5ae398b8 --- /dev/null +++ b/Netch/Models/Settings/TUNConfig.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; + +namespace Netch.Models +{ + /// + /// TUN/TAP 适配器配置类 + /// + public class TUNConfig + { + /// + /// 地址 + /// + public string Address { get; set; } = "10.0.236.10"; + + /// + /// DNS + /// + public string HijackDNS { get; set; } = $"tcp://{Constants.DefaultPrimaryDNS}"; + + /// + /// 网关 + /// + public string Gateway { get; set; } = "10.0.236.1"; + + /// + /// 掩码 + /// + public string Netmask { get; set; } = "255.255.255.0"; + + /// + /// 模式 2 下是否代理 DNS + /// + public bool ProxyDNS { get; set; } = false; + + /// + /// 使用自定义 DNS 设置 + /// + public bool UseCustomDNS { get; set; } = false; + + /// + /// Global bypass IPs + /// + public List BypassIPs { get; set; } = new(); + } +} \ No newline at end of file diff --git a/Netch/Models/Settings/V2rayConfig.cs b/Netch/Models/Settings/V2rayConfig.cs new file mode 100644 index 00000000..f3bbdfe0 --- /dev/null +++ b/Netch/Models/Settings/V2rayConfig.cs @@ -0,0 +1,15 @@ +namespace Netch.Models +{ + public class V2rayConfig + { + public bool AllowInsecure { get; set; } = false; + + public KcpConfig KcpConfig { get; set; } = new(); + + public bool UseMux { get; set; } = false; + + public bool V2rayNShareLink { get; set; } = true; + + public bool XrayCone { get; set; } = true; + } +} \ No newline at end of file diff --git a/Netch/Netch.csproj b/Netch/Netch.csproj index ab46e681..192cc009 100644 --- a/Netch/Netch.csproj +++ b/Netch/Netch.csproj @@ -32,9 +32,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -49,10 +49,8 @@ - - - - + + @@ -68,6 +66,9 @@ True Resources.resx + + UserControl + diff --git a/Netch/Netch.cs b/Netch/Program.cs similarity index 98% rename from Netch/Netch.cs rename to Netch/Program.cs index e4b83ff3..97d5d49c 100644 --- a/Netch/Netch.cs +++ b/Netch/Program.cs @@ -25,9 +25,9 @@ using Windows.Win32.UI.WindowsAndMessaging; namespace Netch { - public static class Netch + public static class Program { - public static readonly SingleInstanceService SingleInstance = new($"Global\\{nameof(Netch)}"); + public static readonly SingleInstanceService SingleInstance = new($"Global\\{nameof(Program)}"); internal static HWND ConsoleHwnd { get; private set; } @@ -115,12 +115,14 @@ namespace Netch Log.Information("SHA256: {Hash}", $"{Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); Log.Information("System Language: {Language}", CultureInfo.CurrentCulture.Name); +#if RELEASE if (Log.IsEnabled(LogEventLevel.Debug)) { // TODO log level setting Task.Run(() => Log.Debug("Third-party Drivers:\n{Drivers}", string.Join(Constants.EOF, SystemInfo.SystemDrivers(false)))).Forget(); Task.Run(() => Log.Debug("Running Processes: \n{Processes}", string.Join(Constants.EOF, SystemInfo.Processes(false)))).Forget(); } +#endif } private static void CheckClr() diff --git a/Netch/Properties/AssemblyInfo.cs b/Netch/Properties/AssemblyInfo.cs index 72b75921..62965d69 100644 --- a/Netch/Properties/AssemblyInfo.cs +++ b/Netch/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ -using Netch.Controllers; -using System.Reflection; +using System.Reflection; using System.Runtime.InteropServices; +using Netch.Controllers; // 有关程序集的一般信息由以下 // 控制。更改这些特性值可修改 @@ -13,9 +13,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCopyright(UpdateChecker.Copyright)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -#if NET [assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")] -#endif // 将 ComVisible 设置为 false 会使此程序集中的类型 //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 diff --git a/Netch/Resources/zh-CN b/Netch/Resources/zh-CN index 2440d839..7bcd094a 100644 --- a/Netch/Resources/zh-CN +++ b/Netch/Resources/zh-CN @@ -39,6 +39,10 @@ "Edit Process Mode": "修改进程模式", "Create Route Table Rule": "创建路由表规则", "Edit Route Table Rule": "修改路由表规则", + "Reload Modes": "重新加载模式", + "Handle rules": "处理规则", + "Bypass rules": "分流规则", + "Handle DNS through proxy": "经过代理处理 DNS", "Address": "地址", "Username": "用户名", @@ -110,7 +114,6 @@ "Remark": "备注", "Filename": "文件名", - "Use Custom Filename": "使用自定义文件名", "Add": "添加", "Scan": "扫描", "Save": "保存", @@ -148,7 +151,7 @@ "Allow other Devices to connect": "允许其他设备连入", "Netmask": "子网掩码", "Gateway": "网关", - "Use Custom DNS": "使用自定义 DNS", + "Use custom DNS": "使用自定义 DNS", "Proxy DNS in Proxy Rule IPs Mode": "在 代理规则IP 模式下代理 DNS", "Exit when closed": "关闭时退出", "Stop when exited": "退出时停止", @@ -156,10 +159,16 @@ "Check update when opened": "打开软件时检查更新", "Check Beta update": "检查 Beta 更新", "Update Servers when opened": "打开软件时更新服务器", - "Filter Protocol": "Filter 协议", - "Handle process's DNS Hijack": "被代理进程 DNS 劫持", - "Child Process Handle": "子进程代理", - "ICMP Delay(ms)": "ICMP 延迟(毫秒)", + "Handle ICMP": "处理 ICMP", + "Handle TCP": "处理 TCP", + "Handle UDP": "处理 UDP", + "Handle DNS (DNS hijacking)": "处理 DNS(DNS 劫持)", + "Handle handled process's DNS": "处理被处理进程 DNS", + "Handle local loopback": "处理本地回环", + "Handle LAN": "处理局域网", + "Handle child process": "处理子进程", + "ICMP delay(ms)": "ICMP 延迟(毫秒)", + "Mode specific options": "模式专用设置", "Profile Count": "快捷配置数量", "Delay test after start(sec)": "启动后延迟测试(秒)", "Ping Protocol": "延迟测试协议", diff --git a/Netch/Services/ModeService.cs b/Netch/Services/ModeService.cs new file mode 100644 index 00000000..9d9ee212 --- /dev/null +++ b/Netch/Services/ModeService.cs @@ -0,0 +1,115 @@ +using System; +using System.IO; +using Netch.Controllers; +using Netch.Interfaces; +using Netch.Models; +using Netch.Models.Modes; +using Netch.Utils; +using Serilog; + +namespace Netch.Services +{ + public class ModeService + { + public static readonly ModeService Instance = new(); + + public string ModeDirectoryFullName => Path.Combine(Global.NetchDir, "mode"); + + public string GetRelativePath(string fullName) + { + var length = ModeDirectoryFullName.Length; + if (!ModeDirectoryFullName.EndsWith("\\")) + length++; + + return fullName.Substring(length); + } + + public string GetFullPath(string relativeName) + { + return Path.Combine(ModeDirectoryFullName, relativeName); + } + + public void Load() + { + Global.Modes.Clear(); + LoadCore(ModeDirectoryFullName); + Sort(); + Global.MainForm.LoadModes(); + } + + private void LoadCore(string modeDirectory) + { + foreach (var directory in Directory.GetDirectories(modeDirectory)) + LoadCore(directory); + + // skip Directory with a disabled file in + if (File.Exists(Path.Combine(modeDirectory, Constants.DisableModeDirectoryFileName))) + return; + + foreach (var file in Directory.GetFiles(modeDirectory)) + { + try + { + Global.Modes.Add(ModeHelper.LoadMode(file)); + } + catch (NotSupportedException) + { + // ignored + } + catch (Exception e) + { + Log.Warning(e, "Load mode \"{FileName}\" failed", file); + } + } + } + + private static void Sort() + { + // TODO better sort need to discuss + // TODO replace Mode Collection type + Global.Modes.Sort((a, b) => string.Compare(a.i18NRemark, b.i18NRemark, StringComparison.Ordinal)); + } + + public void Add(Mode mode) + { + if (mode.FullName == null) + throw new InvalidOperationException(); + + Global.Modes.Add(mode); + Sort(); + Global.MainForm.ModeComboBox.Items.Insert(Global.Modes.IndexOf(mode), mode); + + mode.WriteFile(); + } + + public static void Delete(Mode mode) + { + if (mode.FullName == null) + throw new ArgumentException(nameof(mode.FullName)); + + Global.MainForm.ModeComboBox.Items.Remove(mode); + Global.Modes.Remove(mode); + + if (File.Exists(mode.FullName)) + File.Delete(mode.FullName); + } + + public static IModeController GetModeControllerByType(ModeType type, out ushort? port, out string portName) + { + port = null; + portName = string.Empty; + switch (type) + { + case ModeType.ProcessMode: + return new NFController(); + case ModeType.TunMode: + return new TUNController(); + case ModeType.ShareMode: + return new PcapController(); + default: + Log.Error("Unknown Mode Type \"{Type}\"", (int)type); + throw new MessageException("Unknown Mode Type"); + } + } + } +} \ No newline at end of file diff --git a/Netch/Services/Updater.cs b/Netch/Services/Updater.cs index 8af00f9b..139271dd 100644 --- a/Netch/Services/Updater.cs +++ b/Netch/Services/Updater.cs @@ -13,19 +13,13 @@ namespace Netch.Services { public class Updater { - #region Static - - #endregion - - #region Class - private string UpdateFile { get; } private string InstallDirectory { get; } private readonly string _tempDirectory; private static readonly string[] KeepDirectories = { "data", "mode\\Custom", "logging" }; - private static readonly string[] KeepFiles = { ModeHelper.DisableModeDirectoryFileName }; + private static readonly string[] KeepFiles = { Constants.DisableModeDirectoryFileName }; internal Updater(string updateFile, string installDirectory) { @@ -142,7 +136,5 @@ namespace Netch.Services } #endregion - - #endregion } } \ No newline at end of file diff --git a/Netch/Utils/DnsUtils.cs b/Netch/Utils/DnsUtils.cs index 371cc455..cab7e3b0 100644 --- a/Netch/Utils/DnsUtils.cs +++ b/Netch/Utils/DnsUtils.cs @@ -1,7 +1,5 @@ using System; using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; @@ -64,8 +62,7 @@ namespace Netch.Utils Cache6.Add(hostname, result); break; default: - Trace.Assert(false); - break; + throw new ArgumentOutOfRangeException(); } return result; @@ -74,34 +71,12 @@ namespace Netch.Utils return null; } - /// - /// 查询 - /// - /// 主机名 - /// public static void ClearCache() { Cache.Clear(); Cache6.Clear(); } - public static IEnumerable Split(string dns) - { - return dns.SplitRemoveEmptyEntriesAndTrimEntries(','); - } - - public static bool TrySplit(string value, out IEnumerable result, ushort maxCount = 0) - { - result = Split(value).ToArray(); - - return maxCount == 0 || result.Count() <= maxCount && result.All(ip => IPAddress.TryParse(ip, out _)); - } - - public static string Join(IEnumerable dns) - { - return string.Join(",", dns); - } - public static string AppendPort(string host, ushort port = 53) { if (!host.Contains(':')) @@ -109,13 +84,5 @@ namespace Netch.Utils return host; } - - public static string AppendScheme(string value, string scheme = "tcp") - { - if (!value.Contains(Uri.SchemeDelimiter)) - return scheme + Uri.SchemeDelimiter + value; - - return value; - } } } \ No newline at end of file diff --git a/Netch/Utils/ModeHelper.cs b/Netch/Utils/ModeHelper.cs index 7328cefc..4bb7e87a 100644 --- a/Netch/Utils/ModeHelper.cs +++ b/Netch/Utils/ModeHelper.cs @@ -1,147 +1,142 @@ using System; using System.IO; using System.Linq; -using System.Reactive.Linq; -using Netch.Controllers; -using Netch.Enums; -using Netch.Interfaces; -using Netch.Models; -using Serilog; +using System.Text.Json; +using System.Text.Json.Serialization; +using Netch.JsonConverter; +using Netch.Models.Modes; +using Netch.Models.Modes.ProcessMode; +using Netch.Models.Modes.ShareMode; +using Netch.Models.Modes.TunMode; +using Netch.Services; namespace Netch.Utils { public static class ModeHelper { - public const string DisableModeDirectoryFileName = "disabled"; + private static readonly JsonSerializerOptions JsonSerializerOptions = Global.NewCustomJsonSerializerOptions(); - private static FileSystemWatcher _fileSystemWatcher = null!; - - public static string ModeDirectoryFullName => Path.Combine(Global.NetchDir, "mode"); - - public static bool SuspendWatcher + static ModeHelper() { - get => _fileSystemWatcher.EnableRaisingEvents; - set => _fileSystemWatcher.EnableRaisingEvents = value; + JsonSerializerOptions.Converters.Add(new ModeConverterWithTypeDiscriminator()); + JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.Never; } - public static void InitWatcher() + public static Mode LoadMode(string file) { - _fileSystemWatcher = new FileSystemWatcher(ModeDirectoryFullName) + if (file.EndsWith(".json")) + return LoadJsonMode(file); + + if (file.EndsWith(".txt")) + return ReadTxtMode(file); + + throw new NotSupportedException(); + } + + private static Mode LoadJsonMode(string file) + { + using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true); + var mode = JsonSerializer.Deserialize(fs, JsonSerializerOptions) ?? throw new ArgumentNullException(); + mode.FullName = file; + return mode; + } + + public static void WriteFile(this Mode mode) + { + using var fs = new FileStream(mode.FullName, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true); + JsonSerializer.Serialize(fs, mode, JsonSerializerOptions); + } + + private static Mode ReadTxtMode(string file) + { + Mode mode; + var ls = File.ReadAllLines(file); + string modeTypeNum; + + if (ls.First().First() != '#') + throw new FormatException("Not a valid txt mode that begins with meta line"); + + var heads = ls[0][1..].Split(",", StringSplitOptions.TrimEntries); + switch (modeTypeNum = heads.ElementAtOrDefault(1) ?? "0") { - NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, - IncludeSubdirectories = true, - EnableRaisingEvents = true - }; - - var created = Observable.FromEventPattern(h => _fileSystemWatcher.Created += h, - h => _fileSystemWatcher.Created -= h) - .Select(x => x.EventArgs); - - var changed = Observable.FromEventPattern(h => _fileSystemWatcher.Changed += h, - h => _fileSystemWatcher.Changed -= h) - .Select(x => x.EventArgs); - - var deleted = Observable.FromEventPattern(h => _fileSystemWatcher.Deleted += h, - h => _fileSystemWatcher.Deleted -= h) - .Select(x => x.EventArgs); - - var renamed = Observable.FromEventPattern(h => _fileSystemWatcher.Renamed += h, - h => _fileSystemWatcher.Renamed -= h) - .Select(x => x.EventArgs); - - var o = Observable.Merge(created, deleted, renamed, changed); - o.Throttle(TimeSpan.FromSeconds(3)).Subscribe(_ => OnModeChange(), exception => Log.Error(exception, "FileSystemWatcherError")); - } - - private static void OnModeChange() - { - Load(); - Global.MainForm.LoadModes(); - } - - public static string GetRelativePath(string fullName) - { - var length = ModeDirectoryFullName.Length; - if (!ModeDirectoryFullName.EndsWith("\\")) - length++; - - return fullName.Substring(length); - } - - public static string GetFullPath(string relativeName) - { - return Path.Combine(ModeDirectoryFullName, relativeName); - } - - public static void Load() - { - Global.Modes.Clear(); - LoadCore(ModeDirectoryFullName); - Sort(); - } - - private static void LoadCore(string modeDirectory) - { - try - { - foreach (var directory in Directory.GetDirectories(modeDirectory)) - LoadCore(directory); - - // skip Directory with a disabled file in - if (File.Exists(Path.Combine(modeDirectory, DisableModeDirectoryFileName))) - return; - - foreach (var file in Directory.GetFiles(modeDirectory).Where(f => f.EndsWith(".txt"))) - try - { - Global.Modes.Add(new Mode(file)); - } - catch (Exception e) - { - Log.Warning(e, "Load mode \"{FileName}\" failed", file); - } - } - catch - { - // ignored - } - } - - private static void Sort() - { - Global.Modes.Sort((a, b) => string.Compare(a.Remark, b.Remark, StringComparison.Ordinal)); - } - - public static void Delete(Mode mode) - { - if (mode.FullName == null) - throw new ArgumentException(nameof(mode.FullName)); - - Global.MainForm.ModeComboBox.Items.Remove(mode); - Global.Modes.Remove(mode); - - if (File.Exists(mode.FullName)) - File.Delete(mode.FullName); - } - - public static (IModeController, ModeFeature) GetModeControllerByType(ModeType type, out ushort? port, out string portName) - { - port = null; - portName = string.Empty; - switch (type) - { - case ModeType.Process: - return (new NFController(), ModeFeature.SupportIPv6 | ModeFeature.SupportSocks5Auth); - case ModeType.ProxyRuleIPs: - return (new TUNController(), ModeFeature.SupportSocks5Auth); - case ModeType.BypassRuleIPs: - return (new TUNController(), ModeFeature.SupportSocks5Auth); - case ModeType.Pcap2Socks: - return (new PcapController(), 0); + case "0": + mode = new Redirector { FullName = file }; + break; + case "1": + case "2": + mode = new TunMode { FullName = file }; + break; + case "6": + mode = new ShareMode { FullName = file }; + break; default: - Log.Error("Unknown Mode Type \"{Type}\"", (int)type); - throw new MessageException("Unknown Mode Type"); + throw new ArgumentOutOfRangeException(); } + + mode.Remark.Add("en", heads[0]); + + foreach (var l in ls.Skip(1)) + { + if (l.IsNullOrWhiteSpace()) + continue; + + if (l.StartsWith("//")) + continue; + + Mode? includeMode = null; + if (l.StartsWith("#include")) + { + var relativePath = l["#include ".Length..].Replace("<", "").Replace(">", "").Replace(".h", ".txt").Trim(); + includeMode = ReadTxtMode(ModeService.Instance.GetFullPath(relativePath)); + } + + switch (mode) + { + case Redirector processMode: + if (includeMode is Redirector pMode) + { + processMode.Bypass.AddRange(pMode.Bypass); + processMode.Handle.AddRange(pMode.Handle); + } + else if (l.StartsWith("!")) + processMode.Bypass.Add(l); + else + processMode.Handle.Add(l); + + break; + case ShareMode shareMode: + shareMode.Argument = l; + break; + case TunMode tunMode: + if (includeMode is TunMode tMode) + { + tunMode.Bypass.AddRange(tMode.Bypass); + tMode.Handle.AddRange(tMode.Handle); + break; + } + + switch (modeTypeNum) + { + case "1": + tunMode.Handle.Add(l); + break; + case "2": + tunMode.Bypass.Add(l); + break; + } + + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + if (modeTypeNum == "2") + ((TunMode)mode).Handle.Add("0.0.0.0/0"); + + return mode; } } } \ No newline at end of file diff --git a/Netch/Utils/NetworkInterfaceUtils.cs b/Netch/Utils/NetworkInterfaceUtils.cs index 2ba56214..663b0b16 100644 --- a/Netch/Utils/NetworkInterfaceUtils.cs +++ b/Netch/Utils/NetworkInterfaceUtils.cs @@ -5,8 +5,8 @@ using System.Management; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -using Netch.Models; using Windows.Win32; +using Netch.Models; namespace Netch.Utils { @@ -15,14 +15,15 @@ namespace Netch.Utils public static NetworkInterface GetBest(AddressFamily addressFamily = AddressFamily.InterNetwork) { string ipAddress; - if (addressFamily == AddressFamily.InterNetwork) + switch (addressFamily) { - ipAddress = "114.114.114.114"; - } - else - { - Trace.Assert(addressFamily == AddressFamily.InterNetworkV6); - throw new NotImplementedException(); + case AddressFamily.InterNetwork: + ipAddress = "114.114.114.114"; + break; + case AddressFamily.InterNetworkV6: + throw new NotImplementedException(); + default: + throw new InvalidOperationException(); } if (PInvoke.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0), 0, out var route) != 0) diff --git a/Netch/Utils/PortHelper.cs b/Netch/Utils/PortHelper.cs index d5a62638..1a51abde 100644 --- a/Netch/Utils/PortHelper.cs +++ b/Netch/Utils/PortHelper.cs @@ -37,33 +37,41 @@ namespace Netch.Utils if (port == 0) throw new ArgumentOutOfRangeException(); - if (inet != AddressFamily.InterNetwork) - Trace.Assert(inet == AddressFamily.InterNetworkV6); - - var process = new List(); - unsafe + switch (inet) { - uint err; - uint size = 0; - PInvoke.GetExtendedTcpTable(default, ref size, false, (uint)inet, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER, 0); // get size - var tcpTable = (MIB_TCPTABLE_OWNER_PID*)Marshal.AllocHGlobal((int)size); - - if ((err = PInvoke.GetExtendedTcpTable(tcpTable, ref size, false, (uint)inet, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER, 0)) != 0) - throw new Win32Exception((int)err); - - for (var i = 0; i < tcpTable -> dwNumEntries; i++) + case AddressFamily.InterNetwork: { - var row = tcpTable -> table.ReadOnlyItemRef(i); + var process = new List(); + unsafe + { + uint err; + uint size = 0; + PInvoke.GetExtendedTcpTable(default, ref size, false, (uint)inet, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER, 0); // get size + var tcpTable = (MIB_TCPTABLE_OWNER_PID*)Marshal.AllocHGlobal((int)size); - if (row.dwOwningPid is 0 or 4) - continue; + if ((err = PInvoke.GetExtendedTcpTable(tcpTable, ref size, false, (uint)inet, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER, 0)) != + 0) + throw new Win32Exception((int)err); - if (PInvoke.ntohs((ushort)row.dwLocalPort) == port) - process.Add(Process.GetProcessById((int)row.dwOwningPid)); + for (var i = 0; i < tcpTable -> dwNumEntries; i++) + { + var row = tcpTable -> table.ReadOnlyItemRef(i); + + if (row.dwOwningPid is 0 or 4) + continue; + + if (PInvoke.ntohs((ushort)row.dwLocalPort) == port) + process.Add(Process.GetProcessById((int)row.dwOwningPid)); + } + } + + return process; } + case AddressFamily.InterNetworkV6: + throw new NotImplementedException(); + default: + throw new InvalidOperationException(); } - - return process; } private static void GetReservedPortRange(PortType portType, ref List targetList) @@ -136,8 +144,7 @@ namespace Netch.Utils break; default: - Trace.Assert(false); - return; + throw new ArgumentOutOfRangeException(nameof(type), type, null); } } diff --git a/Netch/Utils/i18N.cs b/Netch/Utils/i18N.cs index 72c57793..1d1d81cf 100644 --- a/Netch/Utils/i18N.cs +++ b/Netch/Utils/i18N.cs @@ -13,12 +13,10 @@ namespace Netch.Utils { public static class i18N { -#if NET static i18N() { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); } -#endif /// /// 数据 diff --git a/UnitTest/UnitTest.csproj b/UnitTest/UnitTest.csproj index e432a938..55ce09ec 100644 --- a/UnitTest/UnitTest.csproj +++ b/UnitTest/UnitTest.csproj @@ -7,9 +7,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive