diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 2a0c340e..6a28f0d1 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -55,7 +55,7 @@ namespace Netch.Controllers public static void Start(Server server, Mode mode) { - Global.Logger.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}"); + Global.Logger.Info($"启动主控制器: {server.Type} [{(int)mode.Type}]{mode.Remark}"); Server = server; Mode = mode; diff --git a/Netch/Controllers/NFController.cs b/Netch/Controllers/NFController.cs index 6d3572b8..1cc3bca9 100644 --- a/Netch/Controllers/NFController.cs +++ b/Netch/Controllers/NFController.cs @@ -149,7 +149,7 @@ namespace Netch.Controllers { Dial(NameList.TYPE_CLRNAME, ""); var invalidList = new List(); - foreach (var s in mode.FullRule) + foreach (var s in mode.GetRules()) { if (s.StartsWith("!")) { diff --git a/Netch/Controllers/PcapController.cs b/Netch/Controllers/PcapController.cs index ef6f280b..6c61bbfa 100644 --- a/Netch/Controllers/PcapController.cs +++ b/Netch/Controllers/PcapController.cs @@ -40,7 +40,7 @@ namespace Netch.Controllers else argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}"); - argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}"); + argument.Append($" {mode.GetRules().FirstOrDefault() ?? "-P n"}"); StartInstanceAuto(argument.ToString()); } diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index fb0dc513..b404030d 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -4,6 +4,7 @@ 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; @@ -95,8 +96,8 @@ namespace Netch.Controllers _tunAdapter = new TunAdapter(); switch (mode.Type) { - case 1 when Global.Settings.TUNTAP.ProxyDNS: - case 2: + case ModeType.ProxyRuleIPs when Global.Settings.TUNTAP.ProxyDNS: + case ModeType.BypassRuleIPs: _tunAdapter.NetworkInterface.SetDns(DummyDns); break; } @@ -167,10 +168,10 @@ namespace Netch.Controllers switch (mode.Type) { - case 1: + case ModeType.ProxyRuleIPs: // 代理规则 IP Global.Logger.Info("代理 → 规则 IP"); - RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP); + RouteAction(Action.Create, mode.GetRules(), RouteType.TUNTAP); if (Global.Settings.TUNTAP.ProxyDNS) { @@ -186,17 +187,17 @@ namespace Netch.Controllers } break; - case 2: + case ModeType.BypassRuleIPs: // 绕过规则 IP Global.Logger.Info("绕行 → 规则 IP"); - RouteAction(Action.Create, mode.FullRule, RouteType.Outbound); + RouteAction(Action.Create, mode.GetRules(), RouteType.Outbound); break; } #endregion - if (mode.Type == 2) + if (mode.Type == ModeType.BypassRuleIPs) { Global.Logger.Info("代理 → 全局"); SetInterface(RouteType.TUNTAP, 0); @@ -225,7 +226,7 @@ namespace Netch.Controllers RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP); _directIPs.Clear(); _proxyIPs.Clear(); - if (mode.Type == 2) + if (mode.Type == ModeType.BypassRuleIPs) { SetInterface(RouteType.Outbound); } diff --git a/Netch/Enums/Modes.cs b/Netch/Enums/Modes.cs new file mode 100644 index 00000000..a3d70445 --- /dev/null +++ b/Netch/Enums/Modes.cs @@ -0,0 +1,10 @@ +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/MainForm.cs b/Netch/Forms/MainForm.cs index 81181c9b..a6bf8e60 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using Netch.Enums; using Netch.Interfaces; namespace Netch.Forms @@ -727,13 +728,13 @@ namespace Netch.Forms switch (mode.Type) { - case 0: + case ModeType.Process: Hide(); new Process(mode).ShowDialog(); Show(); break; - case 1: - case 2: + case ModeType.ProxyRuleIPs: + case ModeType.BypassRuleIPs: Hide(); new Route(mode).ShowDialog(); Show(); @@ -1422,7 +1423,7 @@ namespace Netch.Forms // 绘制 模式行数 字符串 TextRenderer.DrawText(e.Graphics, - item.Rule.Count.ToString(), + item.Content.Count.ToString(), cbx.Font, new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y), Color.Black, diff --git a/Netch/Forms/Mode/Process.cs b/Netch/Forms/Mode/Process.cs index b2f45769..9e4b5302 100644 --- a/Netch/Forms/Mode/Process.cs +++ b/Netch/Forms/Mode/Process.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; +using Netch.Enums; namespace Netch.Forms.Mode { @@ -24,7 +25,7 @@ namespace Netch.Forms.Mode /// 模式 public Process(Models.Mode? mode = null) { - if (mode != null && mode.Type is not 0) + if (mode != null && mode.Type is not ModeType.Process) throw new ArgumentOutOfRangeException(); InitializeComponent(); @@ -62,7 +63,7 @@ namespace Netch.Forms.Mode RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged; RemarkTextBox.Text = _mode.Remark; FilenameTextBox.Text = _mode.RelativePath; - RuleAddRange(_mode.Rule); + RuleAddRange(_mode.Content); } i18N.TranslateForm(this); @@ -116,8 +117,8 @@ namespace Netch.Forms.Mode if (_mode != null) { _mode.Remark = RemarkTextBox.Text; - _mode.Rule.Clear(); - _mode.Rule.AddRange(RuleRichTextBox.Lines); + _mode.Content.Clear(); + _mode.Content.AddRange(RuleRichTextBox.Lines); _mode.WriteFile(); MessageBoxX.Show(i18N.Translate("Mode updated successfully")); @@ -134,11 +135,11 @@ namespace Netch.Forms.Mode var mode = new Models.Mode(fullName) { - Type = 0, + Type = ModeType.Process, Remark = RemarkTextBox.Text }; - mode.Rule.AddRange(RuleRichTextBox.Lines); + mode.Content.AddRange(RuleRichTextBox.Lines); mode.WriteFile(); MessageBoxX.Show(i18N.Translate("Mode added successfully")); diff --git a/Netch/Forms/Mode/Route.cs b/Netch/Forms/Mode/Route.cs index b69a5391..8eecd5da 100644 --- a/Netch/Forms/Mode/Route.cs +++ b/Netch/Forms/Mode/Route.cs @@ -4,18 +4,20 @@ using Netch.Utils; using System; using System.IO; using System.Windows.Forms; +using Netch.Enums; namespace Netch.Forms.Mode { public partial class Route : Form { - private readonly TagItem[] _items = { new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs") }; + private readonly TagItem[] _items = + { new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") }; private readonly Models.Mode? _mode; public Route(Models.Mode? mode = null) { - if (mode != null && mode.Type is not (1 or 2)) + if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs)) throw new ArgumentOutOfRangeException(); _mode = mode; @@ -37,7 +39,7 @@ namespace Netch.Forms.Mode RemarkTextBox.Text = _mode.Remark; comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor FilenameTextBox.Text = _mode.RelativePath; - richTextBox1.Lines = _mode.Rule.ToArray(); + richTextBox1.Lines = _mode.Content.ToArray(); } i18N.TranslateForm(this); @@ -60,9 +62,9 @@ namespace Netch.Forms.Mode if (_mode != null) { _mode.Remark = RemarkTextBox.Text; - _mode.Rule.Clear(); - _mode.Rule.AddRange(richTextBox1.Lines); - _mode.Type = (int)comboBox1.SelectedValue; + _mode.Content.Clear(); + _mode.Content.AddRange(richTextBox1.Lines); + _mode.Type = (ModeType)comboBox1.SelectedValue; _mode.WriteFile(); MessageBoxX.Show(i18N.Translate("Mode updated successfully")); @@ -79,11 +81,11 @@ namespace Netch.Forms.Mode var mode = new Models.Mode(fullName) { - Type = (int)comboBox1.SelectedValue, + Type = (ModeType)comboBox1.SelectedValue, Remark = RemarkTextBox.Text }; - mode.Rule.AddRange(richTextBox1.Lines); + mode.Content.AddRange(richTextBox1.Lines); mode.WriteFile(); MessageBoxX.Show(i18N.Translate("Mode added successfully")); diff --git a/Netch/Models/Mode.cs b/Netch/Models/Mode.cs index a1ebcdd5..eac280e9 100644 --- a/Netch/Models/Mode.cs +++ b/Netch/Models/Mode.cs @@ -4,138 +4,126 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Netch.Enums; namespace Netch.Models { public class Mode { - private readonly Lazy> _lazyRule; - - public string? FullName { get; private set; } - + /// + /// + /// + /// Mode File FullPath + /// + /// public Mode(string? fullName) { - _lazyRule = new Lazy>(ReadRules); - if (fullName == null) - return; - FullName = fullName; - if (!File.Exists(FullName)) + if (FullName == null || !File.Exists(FullName)) return; - var text = File.ReadLines(FullName).First(); - - // load head - if (text.First() != '#') - throw new Exception($"mode {FullName} head not found at Line 0"); - - var split = text.Substring(1).SplitTrimEntries(','); - Remark = split[0]; - - var typeResult = int.TryParse(split.ElementAtOrDefault(1), out var type); - Type = typeResult ? type : 0; - if (!ModeHelper.ModeTypes.Contains(Type)) - throw new NotSupportedException($"not support mode \"[{Type}]{Remark}\"."); + (Remark, Type) = ReadHead(FullName); } + public string? FullName { get; } + /// /// 规则 /// - public List Rule => _lazyRule.Value; + public List Content => _content ??= ReadContent(); + + private List? _content; /// /// 备注 /// public string Remark { get; set; } = ""; - /// - /// 类型 - /// - /// 0. Socks5 + 进程加速 - /// - /// 1. Socks5 + TUN/TAP 规则内 IP CIDR 加速 - /// - /// 2. Socks5 + TUN/TAP 全局,绕过规则内 IP CIDR - /// - /// 3. Socks5 + HTTP 代理(设置到系统代理) - /// - /// 4. Socks5 代理(不设置到系统代理) - /// - /// 5. Socks5 + HTTP 代理(不设置到系统代理) - /// - /// - public int Type { get; set; } = 0; + public ModeType Type { get; set; } = ModeType.Process; /// /// 文件相对路径(必须是存在的文件) /// public string? RelativePath => FullName == null ? null : ModeHelper.GetRelativePath(FullName); - public List FullRule + public IEnumerable GetRules() { - get + var result = new List(); + foreach (var s in Content) { - var result = new List(); - foreach (var s in Rule) + if (string.IsNullOrWhiteSpace(s)) + continue; + + if (s.StartsWith("//")) + continue; + + const string include = "#include"; + if (s.StartsWith(include)) { - if (string.IsNullOrWhiteSpace(s)) - continue; + var relativePath = new StringBuilder(s[include.Length..].Trim()); + relativePath.Replace("<", "").Replace(">", ""); + relativePath.Replace(".h", ".txt"); - if (s.StartsWith("//")) - continue; + var mode = Global.Modes.FirstOrDefault(m => m.RelativePath?.Equals(relativePath.ToString()) ?? false) ?? + throw new MessageException($"{relativePath} file included in {Remark} not found"); - if (s.StartsWith("#include")) - { - var relativePath = new StringBuilder(s.Substring(8).Trim()); - relativePath.Replace("<", ""); - relativePath.Replace(">", ""); - relativePath.Replace(".h", ".txt"); + if (mode == this) + throw new MessageException("Can't self-reference"); - var mode = Global.Modes.FirstOrDefault(m => m.FullName != null && m.RelativePath!.Equals(relativePath.ToString())); + if (mode.Type != Type) + throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode"); - if (mode == null) - throw new MessageException($"{relativePath} file included in {Remark} not found"); + if (mode.Content.Any(rule => rule.StartsWith(include))) + throw new Exception("Cannot reference mode that reference other mode"); - 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.Rule.Any(rule => rule.StartsWith("#include"))) - throw new Exception("Cannot reference mode that reference other mode"); - - result.AddRange(mode.FullRule); - } - else - { - result.Add(s); - } + result.AddRange(mode.GetRules()); + } + else + { + result.Add(s); } - - return result; } + + return result; } - private List ReadRules() + 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 split = text[1..].SplitTrimEntries(','); + + var typeNumber = int.TryParse(split.ElementAtOrDefault(1), out var type) ? type : 0; + if (!Enum.GetValues(typeof(ModeType)).Cast().Contains(typeNumber)) + throw new NotSupportedException($"Not support mode \"{typeNumber}\"."); + + return (split[0], (ModeType)typeNumber); + } + + private List ReadContent() { if (FullName == null || !File.Exists(FullName)) return new List(); - return File.ReadLines(FullName!).Skip(1).ToList(); + return File.ReadLines(FullName).Skip(1).ToList(); } - public void WriteFile(string? fullName = null) + public void ResetContent() { - if (fullName != null) - throw new NotImplementedException(); + _content = null; + } + 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!, ToFileString()); + File.WriteAllText(FullName!, content); } /// @@ -144,16 +132,7 @@ namespace Netch.Models /// 备注 public override string ToString() { - return $"[{Type + 1}] {i18N.Translate(Remark)}"; - } - - /// - /// 获取模式文件字符串 - /// - /// 模式文件字符串 - public string ToFileString() - { - return $"# {Remark}, {Type}{Constants.EOF}{string.Join(Constants.EOF, Rule)}"; + return $"[{(int)Type + 1}] {i18N.Translate(Remark)}"; } } @@ -162,7 +141,7 @@ namespace Netch.Models /// 是否会转发 UDP public static bool TestNatRequired(this Mode mode) { - return mode.Type is 0 or 2; + return mode.Type is ModeType.Process or ModeType.BypassRuleIPs; } } } \ No newline at end of file diff --git a/Netch/Servers/V2ray/Utils/V2rayConfigUtils.cs b/Netch/Servers/V2ray/Utils/V2rayConfigUtils.cs index b019b9af..ccb5e8c9 100644 --- a/Netch/Servers/V2ray/Utils/V2rayConfigUtils.cs +++ b/Netch/Servers/V2ray/Utils/V2rayConfigUtils.cs @@ -3,6 +3,7 @@ using Netch.Servers.V2ray.Models; using System.Collections.Generic; using System.Linq; using System.Text.Json; +using Netch.Enums; using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig; namespace Netch.Servers.V2ray.Utils @@ -65,7 +66,7 @@ namespace Netch.Servers.V2ray.Utils outboundTag = "block" }; - if (mode.Type is 0 or 1 or 2) + if (mode.Type is ModeType.Process or ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs) blockRuleObject.ip.Add("geoip:private"); static bool CheckRuleItem(ref RulesItem rulesItem) diff --git a/Netch/Utils/ModeHelper.cs b/Netch/Utils/ModeHelper.cs index e2c0458c..04503e08 100644 --- a/Netch/Utils/ModeHelper.cs +++ b/Netch/Utils/ModeHelper.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Linq; using Netch.Controllers; +using Netch.Enums; using Netch.Interfaces; using Netch.Models; using Netch.Servers.Shadowsocks; @@ -112,35 +113,33 @@ namespace Netch.Utils { switch (mode.Type) { - case 0: + case ModeType.Process: return server switch { Socks5 => true, Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS => true, _ => false }; - case 1: - case 2: + case ModeType.ProxyRuleIPs: + case ModeType.BypassRuleIPs: return server is Socks5; default: return false; } } - public static readonly int[] ModeTypes = { 0, 1, 2, 6 }; - - public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName) + public static IModeController GetModeControllerByType(ModeType type, out ushort? port, out string portName) { port = null; portName = string.Empty; switch (type) { - case 0: + case ModeType.Process: return new NFController(); - case 1: - case 2: + case ModeType.ProxyRuleIPs: + case ModeType.BypassRuleIPs: return new TUNController(); - case 6: + case ModeType.Pcap2Socks: return new PcapController(); default: Global.Logger.Error("未知模式类型");