From 8fb2bdcee93122edb35a01d9f04cffa842b1eb1b Mon Sep 17 00:00:00 2001
From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com>
Date: Sat, 13 Nov 2021 00:16:37 +0800
Subject: [PATCH] C# 10
---
.editorconfig | 4 +
Netch/Constants.cs | 53 +-
Netch/Controllers/DNSController.cs | 43 +-
Netch/Controllers/Guard.cs | 306 +-
Netch/Controllers/MainController.cs | 334 +-
Netch/Controllers/NFController.cs | 465 ++-
Netch/Controllers/PcapController.cs | 160 +-
Netch/Controllers/TUNController.cs | 330 +-
Netch/Controllers/UpdateChecker.cs | 180 +-
Netch/Enums/LogLevel.cs | 13 +-
Netch/Enums/State.cs | 83 +-
Netch/Flags.cs | 13 +-
Netch/Forms/AboutForm.cs | 47 +-
Netch/Forms/BindingForm.cs | 143 +-
Netch/Forms/GlobalBypassIPForm.cs | 102 +-
Netch/Forms/LogForm.cs | 133 +-
Netch/Forms/MainForm.cs | 2759 ++++++++---------
Netch/Forms/MessageBoxX.cs | 67 +-
Netch/Forms/ModeForms/ModeEditorUtils.cs | 36 +-
Netch/Forms/ModeForms/ProcessForm.cs | 392 ++-
Netch/Forms/ModeForms/RouteForm.cs | 162 +-
Netch/Forms/ServerForm.cs | 580 ++--
Netch/Forms/SettingForm.cs | 363 ++-
Netch/Forms/SubscriptionForm.cs | 410 ++-
Netch/Forms/SyncGlobalCheckBox.cs | 137 +-
Netch/Global.cs | 80 +-
Netch/Interfaces/IController.cs | 11 +-
Netch/Interfaces/IModeController.cs | 14 +-
Netch/Interfaces/IServerController.cs | 36 +-
Netch/Interfaces/IServerUtil.cs | 59 +-
Netch/Interops/AioDNS.cs | 63 +-
Netch/Interops/Redirector.cs | 139 +-
Netch/Interops/RouteHelper.cs | 152 +-
.../ModeConverterWithTypeDiscriminator.cs | 60 +-
.../ServerConverterWithTypeDiscriminator.cs | 30 +-
Netch/Models/Arguments.cs | 68 +-
Netch/Models/GitHubRelease/Asset.cs | 33 +-
Netch/Models/GitHubRelease/GitHubRelease.cs | 23 +-
Netch/Models/GitHubRelease/GitHubUser.cs | 43 +-
Netch/Models/GitHubRelease/Release.cs | 43 +-
Netch/Models/GitHubRelease/SuffixVersion.cs | 191 +-
Netch/Models/GitHubRelease/VersionUtil.cs | 47 +-
Netch/Models/MessageException.cs | 15 +-
Netch/Models/Modes/Mode.cs | 44 +-
Netch/Models/Modes/ModeFeature.cs | 17 +-
Netch/Models/Modes/ModeType.cs | 33 +-
Netch/Models/Modes/ProcessMode/ProcessMode.cs | 39 +-
Netch/Models/Modes/ShareMode/ShareMode.cs | 13 +-
Netch/Models/Modes/TunMode/TunMode.cs | 13 +-
Netch/Models/NatTypeTestResult.cs | 13 +-
Netch/Models/NetRoute.cs | 64 +-
Netch/Models/NumberRange.cs | 29 +-
Netch/Models/Profile.cs | 47 +-
Netch/Models/Server.cs | 191 +-
Netch/Models/Settings/AioDNSConfig.cs | 15 +-
Netch/Models/Settings/KcpConfig.cs | 21 +-
Netch/Models/Settings/RedirectorConfig.cs | 25 +-
Netch/Models/Settings/Setting.cs | 330 +-
Netch/Models/Settings/TUNConfig.cs | 65 +-
Netch/Models/Settings/V2rayConfig.cs | 17 +-
Netch/Models/StatusText.cs | 75 +-
Netch/Models/Subscription.cs | 39 +-
Netch/Models/TagItem.cs | 25 +-
Netch/NativeMethods.cs | 13 +-
Netch/Netch.csproj | 154 +-
Netch/Program.cs | 364 ++-
.../Shadowsocks/ShadowsocksController.cs | 65 +-
Netch/Servers/Shadowsocks/ShadowsocksForm.cs | 27 +-
.../Servers/Shadowsocks/ShadowsocksServer.cs | 118 +-
Netch/Servers/Shadowsocks/ShadowsocksUtil.cs | 277 +-
.../Shadowsocks/ShareModels/SSDJObject.cs | 63 +-
.../ShareModels/SSDServerJObject.cs | 63 +-
.../ShareModels/ShadowsocksConfig.cs | 29 +-
.../ShadowsocksR/ShadowsocksRController.cs | 75 +-
.../Servers/ShadowsocksR/ShadowsocksRForm.cs | 31 +-
.../ShadowsocksR/ShadowsocksRServer.cs | 182 +-
.../Servers/ShadowsocksR/ShadowsocksRUtil.cs | 246 +-
Netch/Servers/Socks5/Socks5Controller.cs | 23 +-
Netch/Servers/Socks5/Socks5Form.cs | 23 +-
Netch/Servers/Socks5/Socks5LocalServer.cs | 31 +-
Netch/Servers/Socks5/Socks5Server.cs | 69 +-
Netch/Servers/Socks5/Socks5Util.cs | 118 +-
Netch/Servers/Trojan/TrojanConfig.cs | 135 +-
Netch/Servers/Trojan/TrojanController.cs | 78 +-
Netch/Servers/Trojan/TrojanForm.cs | 23 +-
Netch/Servers/Trojan/TrojanServer.cs | 34 +-
Netch/Servers/Trojan/TrojanUtil.cs | 127 +-
.../V2ray/ShareModels/V2rayNJObject.cs | 111 +-
Netch/Servers/V2ray/V2rayConfig.cs | 189 +-
Netch/Servers/V2ray/V2rayConfigUtils.cs | 460 ++-
Netch/Servers/V2ray/V2rayController.cs | 52 +-
Netch/Servers/V2ray/V2rayUtils.cs | 230 +-
Netch/Servers/VLESS/VLESSForm.cs | 66 +-
Netch/Servers/VLESS/VLESSServer.cs | 71 +-
Netch/Servers/VLESS/VLESSUtil.cs | 77 +-
Netch/Servers/VMess/VMessForm.cs | 60 +-
Netch/Servers/VMess/VMessServer.cs | 282 +-
Netch/Servers/VMess/VMessUtil.cs | 193 +-
Netch/Services/ModeService.cs | 204 +-
Netch/Services/Updater.cs | 251 +-
Netch/Utils/Bandwidth.cs | 192 +-
Netch/Utils/Configuration.cs | 240 +-
Netch/Utils/DelayTestHelper.cs | 146 +-
Netch/Utils/DnsUtils.cs | 131 +-
Netch/Utils/Firewall.cs | 125 +-
Netch/Utils/ModeHelper.cs | 224 +-
Netch/Utils/NetworkInterfaceUtils.cs | 141 +-
Netch/Utils/PortHelper.cs | 363 ++-
Netch/Utils/RouteUtils.cs | 131 +-
Netch/Utils/ServerHelper.cs | 46 +-
Netch/Utils/ShareLink.cs | 406 ++-
Netch/Utils/Socks5ServerTestUtils.cs | 166 +-
Netch/Utils/StringExtension.cs | 151 +-
Netch/Utils/SubscriptionUtil.cs | 92 +-
Netch/Utils/SystemInfo.cs | 101 +-
Netch/Utils/Utils.cs | 431 ++-
Netch/Utils/WebUtil.cs | 196 +-
Netch/Utils/i18N.cs | 216 +-
UnitTest/UnitTest.csproj | 2 +-
UnitTest/UnitTest1.cs | 13 +-
120 files changed, 8649 insertions(+), 9015 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 475813fa..7213a91c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -97,3 +97,7 @@ resharper_suggest_var_or_type_simple_types_highlighting = hint
resharper_web_config_module_not_resolved_highlighting = warning
resharper_web_config_type_not_resolved_highlighting = warning
resharper_web_config_wrong_module_highlighting = warning
+
+[*.csproj]
+indent_size = 2
+ij_xml_space_inside_empty_tag = true
\ No newline at end of file
diff --git a/Netch/Constants.cs b/Netch/Constants.cs
index 5ec78658..4323f845 100644
--- a/Netch/Constants.cs
+++ b/Netch/Constants.cs
@@ -1,31 +1,30 @@
-namespace Netch
+namespace Netch;
+
+public static class Constants
{
- public static class Constants
+ public const string TempConfig = "data\\last.json";
+ public const string TempRouteFile = "data\\route.txt";
+
+ public const string AioDnsRuleFile = "bin\\aiodns.conf";
+ public const string NFDriver = "bin\\nfdriver.sys";
+ public const string STUNServersFile = "bin\\stun.txt";
+
+ public const string LogFile = "logging\\application.log";
+
+ public const string OutputTemplate = @"[{Timestamp:yyyy-MM-dd HH:mm:ss}][{Level}] {Message:lj}{NewLine}{Exception}";
+ public const string EOF = "\r\n";
+
+ public const string DefaultGroup = "NONE";
+
+ public static class Parameter
{
- public const string TempConfig = "data\\last.json";
- public const string TempRouteFile = "data\\route.txt";
-
- public const string AioDnsRuleFile = "bin\\aiodns.conf";
- public const string NFDriver = "bin\\nfdriver.sys";
- public const string STUNServersFile = "bin\\stun.txt";
-
- public const string LogFile = "logging\\application.log";
-
- public const string OutputTemplate = @"[{Timestamp:yyyy-MM-dd HH:mm:ss}][{Level}] {Message:lj}{NewLine}{Exception}";
- public const string EOF = "\r\n";
-
- public const string DefaultGroup = "NONE";
-
- public static class Parameter
- {
- public const string Show = "-show";
- public const string ForceUpdate = "-forceUpdate";
- }
-
- 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";
+ public const string Show = "-show";
+ public const string ForceUpdate = "-forceUpdate";
}
+
+ 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/DNSController.cs b/Netch/Controllers/DNSController.cs
index d98a593f..5aee6a3f 100644
--- a/Netch/Controllers/DNSController.cs
+++ b/Netch/Controllers/DNSController.cs
@@ -1,33 +1,30 @@
-using System.IO;
-using System.Threading.Tasks;
-using Netch.Interfaces;
+using Netch.Interfaces;
using Netch.Models;
using static Netch.Interops.AioDNS;
-namespace Netch.Controllers
+namespace Netch.Controllers;
+
+public class DNSController : IController
{
- public class DNSController : IController
+ public string Name => "DNS Service";
+
+ public async Task StartAsync(string listenAddress)
{
- public string Name => "DNS Service";
+ var aioDnsConfig = Global.Settings.AioDNS;
- public async Task StartAsync(string listenAddress)
- {
- var aioDnsConfig = Global.Settings.AioDNS;
+ Dial(NameList.TYPE_REST, "");
+ Dial(NameList.TYPE_LIST, Path.GetFullPath(Constants.AioDnsRuleFile));
+ // TODO remove ListenPort setting
+ Dial(NameList.TYPE_LISN, $"{listenAddress}:{aioDnsConfig.ListenPort}");
+ Dial(NameList.TYPE_CDNS, $"{aioDnsConfig.ChinaDNS}");
+ Dial(NameList.TYPE_ODNS, $"{aioDnsConfig.OtherDNS}");
- Dial(NameList.TYPE_REST, "");
- Dial(NameList.TYPE_LIST, Path.GetFullPath(Constants.AioDnsRuleFile));
- // TODO remove ListenPort setting
- Dial(NameList.TYPE_LISN, $"{listenAddress}:{aioDnsConfig.ListenPort}");
- Dial(NameList.TYPE_CDNS, $"{aioDnsConfig.ChinaDNS}");
- Dial(NameList.TYPE_ODNS, $"{aioDnsConfig.OtherDNS}");
+ if (!await InitAsync())
+ throw new MessageException("AioDNS start failed.");
+ }
- if (!await InitAsync())
- throw new MessageException("AioDNS start failed.");
- }
-
- public async Task StopAsync()
- {
- await FreeAsync();
- }
+ public async Task StopAsync()
+ {
+ await FreeAsync();
}
}
\ No newline at end of file
diff --git a/Netch/Controllers/Guard.cs b/Netch/Controllers/Guard.cs
index 0f369210..c0d78c94 100644
--- a/Netch/Controllers/Guard.cs
+++ b/Netch/Controllers/Guard.cs
@@ -1,182 +1,176 @@
-using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
-using System.IO;
-using System.Linq;
using System.Text;
-using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Netch.Enums;
using Netch.Models;
using Netch.Utils;
-using Serilog;
-namespace Netch.Controllers
+namespace Netch.Controllers;
+
+public abstract class Guard
{
- public abstract class Guard
+ private FileStream? _logFileStream;
+ private StreamWriter? _logStreamWriter;
+
+ /// application path relative of Netch\bin
+ ///
+ /// application output encode
+ protected Guard(string mainFile, bool redirectOutput = true, Encoding? encoding = null)
{
- private FileStream? _logFileStream;
- private StreamWriter? _logStreamWriter;
+ RedirectOutput = redirectOutput;
- /// application path relative of Netch\bin
- ///
- /// application output encode
- protected Guard(string mainFile, bool redirectOutput = true, Encoding? encoding = null)
+ var fileName = Path.GetFullPath($"bin\\{mainFile}");
+
+ if (!File.Exists(fileName))
+ throw new MessageException(i18N.Translate($"bin\\{mainFile} file not found!"));
+
+ Instance = new Process
{
- RedirectOutput = redirectOutput;
-
- var fileName = Path.GetFullPath($"bin\\{mainFile}");
-
- if (!File.Exists(fileName))
- throw new MessageException(i18N.Translate($"bin\\{mainFile} file not found!"));
-
- Instance = new Process
+ StartInfo =
{
- StartInfo =
- {
- FileName = fileName,
- WorkingDirectory = $"{Global.NetchDir}\\bin",
- CreateNoWindow = true,
- UseShellExecute = !RedirectOutput,
- RedirectStandardOutput = RedirectOutput,
- StandardOutputEncoding = RedirectOutput ? encoding : null,
- RedirectStandardError = RedirectOutput,
- StandardErrorEncoding = RedirectOutput ? encoding : null,
- WindowStyle = ProcessWindowStyle.Hidden
- }
- };
- }
-
- protected string LogPath => Path.Combine(Global.NetchDir, $"logging\\{Name}.log");
-
- protected virtual IEnumerable StartedKeywords { get; } = new List();
-
- protected virtual IEnumerable FailedKeywords { get; } = new List();
-
- public abstract string Name { get; }
-
- private State State { get; set; } = State.Waiting;
-
- private bool RedirectOutput { get; }
-
- public Process Instance { get; }
-
- ~Guard()
- {
- _logFileStream?.Dispose();
- _logStreamWriter?.Dispose();
- Instance.Dispose();
- }
-
- protected async Task StartGuardAsync(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
- {
- State = State.Starting;
-
- _logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read);
- _logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true };
-
- Instance.StartInfo.Arguments = argument;
- Instance.Start();
- Global.Job.AddProcess(Instance);
-
- if (priority != ProcessPriorityClass.Normal)
- Instance.PriorityClass = priority;
-
- if (RedirectOutput)
- {
- Task.Run(() => ReadOutput(Instance.StandardOutput)).Forget();
- Task.Run(() => ReadOutput(Instance.StandardError)).Forget();
-
- if (!StartedKeywords.Any())
- {
- // Skip, No started keyword
- State = State.Started;
- return;
- }
-
- // wait ReadOutput change State
- for (var i = 0; i < 1000; i++)
- {
- await Task.Delay(50);
- switch (State)
- {
- case State.Started:
- OnStarted();
- return;
- case State.Stopped:
- await StopGuardAsync();
- OnStartFailed();
- throw new MessageException($"{Name} 控制器启动失败");
- }
- }
-
- await StopGuardAsync();
- throw new MessageException($"{Name} 控制器启动超时");
+ FileName = fileName,
+ WorkingDirectory = $"{Global.NetchDir}\\bin",
+ CreateNoWindow = true,
+ UseShellExecute = !RedirectOutput,
+ RedirectStandardOutput = RedirectOutput,
+ StandardOutputEncoding = RedirectOutput ? encoding : null,
+ RedirectStandardError = RedirectOutput,
+ StandardErrorEncoding = RedirectOutput ? encoding : null,
+ WindowStyle = ProcessWindowStyle.Hidden
}
- }
+ };
+ }
- private void ReadOutput(TextReader reader)
+ protected string LogPath => Path.Combine(Global.NetchDir, $"logging\\{Name}.log");
+
+ protected virtual IEnumerable StartedKeywords { get; } = new List();
+
+ protected virtual IEnumerable FailedKeywords { get; } = new List();
+
+ public abstract string Name { get; }
+
+ private State State { get; set; } = State.Waiting;
+
+ private bool RedirectOutput { get; }
+
+ public Process Instance { get; }
+
+ ~Guard()
+ {
+ _logFileStream?.Dispose();
+ _logStreamWriter?.Dispose();
+ Instance.Dispose();
+ }
+
+ protected async Task StartGuardAsync(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
+ {
+ State = State.Starting;
+
+ _logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read);
+ _logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true };
+
+ Instance.StartInfo.Arguments = argument;
+ Instance.Start();
+ Global.Job.AddProcess(Instance);
+
+ if (priority != ProcessPriorityClass.Normal)
+ Instance.PriorityClass = priority;
+
+ if (RedirectOutput)
{
- string? line;
- while ((line = reader.ReadLine()) != null)
- {
- _logStreamWriter!.WriteLine(line);
- OnReadNewLine(line);
+ Task.Run(() => ReadOutput(Instance.StandardOutput)).Forget();
+ Task.Run(() => ReadOutput(Instance.StandardError)).Forget();
- if (State == State.Starting)
+ if (!StartedKeywords.Any())
+ {
+ // Skip, No started keyword
+ State = State.Started;
+ return;
+ }
+
+ // wait ReadOutput change State
+ for (var i = 0; i < 1000; i++)
+ {
+ await Task.Delay(50);
+ switch (State)
{
- if (StartedKeywords.Any(s => line.Contains(s)))
- State = State.Started;
- else if (FailedKeywords.Any(s => line.Contains(s)))
- {
+ case State.Started:
+ OnStarted();
+ return;
+ case State.Stopped:
+ await StopGuardAsync();
OnStartFailed();
- State = State.Stopped;
- }
+ throw new MessageException($"{Name} 控制器启动失败");
}
}
- State = State.Stopped;
- }
-
- public virtual async Task StopAsync()
- {
await StopGuardAsync();
- }
-
- protected async Task StopGuardAsync()
- {
- _logStreamWriter?.Close();
- _logFileStream?.Close();
-
- try
- {
- if (Instance is { HasExited: false })
- {
- Instance.Kill();
- await Instance.WaitForExitAsync();
- }
- }
- catch (Win32Exception e)
- {
- Log.Error(e, "Stop {Name} failed", Instance.ProcessName);
- }
- catch
- {
- // ignored
- }
- }
-
- protected virtual void OnStarted()
- {
- }
-
- protected virtual void OnReadNewLine(string line)
- {
- }
-
- protected virtual void OnStartFailed()
- {
- Utils.Utils.Open(LogPath);
+ throw new MessageException($"{Name} 控制器启动超时");
}
}
+
+ private void ReadOutput(TextReader reader)
+ {
+ string? line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ _logStreamWriter!.WriteLine(line);
+ OnReadNewLine(line);
+
+ if (State == State.Starting)
+ {
+ if (StartedKeywords.Any(s => line.Contains(s)))
+ State = State.Started;
+ else if (FailedKeywords.Any(s => line.Contains(s)))
+ {
+ OnStartFailed();
+ State = State.Stopped;
+ }
+ }
+ }
+
+ State = State.Stopped;
+ }
+
+ public virtual async Task StopAsync()
+ {
+ await StopGuardAsync();
+ }
+
+ protected async Task StopGuardAsync()
+ {
+ _logStreamWriter?.Close();
+ _logFileStream?.Close();
+
+ try
+ {
+ if (Instance is { HasExited: false })
+ {
+ Instance.Kill();
+ await Instance.WaitForExitAsync();
+ }
+ }
+ catch (Win32Exception e)
+ {
+ Log.Error(e, "Stop {Name} failed", Instance.ProcessName);
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+
+ protected virtual void OnStarted()
+ {
+ }
+
+ protected virtual void OnReadNewLine(string line)
+ {
+ }
+
+ protected virtual void OnStartFailed()
+ {
+ Utils.Utils.Open(LogPath);
+ }
}
\ No newline at end of file
diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs
index e904bf8d..dd66e14e 100644
--- a/Netch/Controllers/MainController.cs
+++ b/Netch/Controllers/MainController.cs
@@ -1,8 +1,4 @@
-using System;
using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Netch.Interfaces;
using Netch.Models;
@@ -10,193 +6,191 @@ using Netch.Models.Modes;
using Netch.Servers;
using Netch.Services;
using Netch.Utils;
-using Serilog;
-namespace Netch.Controllers
+namespace Netch.Controllers;
+
+public static class MainController
{
- public static class MainController
+ public static Socks5Server? Socks5Server { get; private set; }
+
+ public static Server? Server { get; private set; }
+
+ public static Mode? Mode { get; private set; }
+
+ public static IServerController? ServerController { get; private set; }
+
+ public static IModeController? ModeController { get; private set; }
+
+ private static readonly AsyncSemaphore Lock = new(1);
+
+ public static async Task StartAsync(Server server, Mode mode)
{
- public static Socks5Server? Socks5Server { get; private set; }
+ using var releaser = await Lock.EnterAsync();
- public static Server? Server { get; private set; }
+ Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.i18NRemark}");
- public static Mode? Mode { get; private set; }
+ if (await DnsUtils.LookupAsync(server.Hostname) == null)
+ throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
- public static IServerController? ServerController { get; private set; }
+ // TODO Disable NAT Type Test setting
+ // cache STUN Server ip to prevent "Wrong STUN Server"
+ DnsUtils.LookupAsync(Global.Settings.STUN_Server).Forget();
- public static IModeController? ModeController { get; private set; }
+ Server = server;
+ Mode = mode;
- private static readonly AsyncSemaphore Lock = new(1);
+ await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules));
- public static async Task StartAsync(Server server, Mode mode)
+ try
{
- using var releaser = await Lock.EnterAsync();
+ ModeController = ModeService.GetModeControllerByType(mode.Type, out var modePort, out var portName);
- Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.i18NRemark}");
+ if (modePort != null)
+ TryReleaseTcpPort((ushort)modePort, portName);
- if (await DnsUtils.LookupAsync(server.Hostname) == null)
- throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
-
- // TODO Disable NAT Type Test setting
- // cache STUN Server ip to prevent "Wrong STUN Server"
- DnsUtils.LookupAsync(Global.Settings.STUN_Server).Forget();
-
- Server = server;
- Mode = mode;
-
- await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules));
-
- try
+ if (Server is Socks5Server socks5 && (!socks5.Auth() || ModeController.Features.HasFlag(ModeFeature.SupportSocks5Auth)))
{
- 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() || ModeController.Features.HasFlag(ModeFeature.SupportSocks5Auth)))
- {
- Socks5Server = socks5;
- }
- else
- {
- // Start Server Controller to get a local socks5 server
- Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}");
-
- ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
- Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
-
- TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5");
- Socks5Server = await ServerController.StartAsync(server);
-
- StatusPortInfoText.Socks5Port = Socks5Server.Port;
- StatusPortInfoText.UpdateShareLan();
- }
-
- // Start Mode Controller
- Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
-
- await ModeController.StartAsync(Socks5Server, mode);
+ Socks5Server = socks5;
}
- catch (Exception e)
+ else
{
- releaser.Dispose();
- await StopAsync();
+ // Start Server Controller to get a local socks5 server
+ Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}");
- switch (e)
- {
- case DllNotFoundException:
- case FileNotFoundException:
- throw new Exception(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"));
- case MessageException:
- throw;
- default:
- Log.Error(e, "Unhandled Exception When Start MainController");
- Utils.Utils.Open(Constants.LogFile);
- throw new MessageException($"{i18N.Translate("Unhandled Exception")}\n{e.Message}");
- }
+ ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
+ Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
+
+ TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5");
+ Socks5Server = await ServerController.StartAsync(server);
+
+ StatusPortInfoText.Socks5Port = Socks5Server.Port;
+ StatusPortInfoText.UpdateShareLan();
}
+
+ // Start Mode Controller
+ Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
+
+ await ModeController.StartAsync(Socks5Server, mode);
}
-
- public static async Task StopAsync()
+ catch (Exception e)
{
- if (Lock.CurrentCount == 0)
- {
- (await Lock.EnterAsync()).Dispose();
- if (ServerController == null && ModeController == null)
- // stopped
- return;
+ releaser.Dispose();
+ await StopAsync();
- // else begin stop
+ switch (e)
+ {
+ case DllNotFoundException:
+ case FileNotFoundException:
+ throw new Exception(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"));
+ case MessageException:
+ throw;
+ default:
+ Log.Error(e, "Unhandled Exception When Start MainController");
+ Utils.Utils.Open(Constants.LogFile);
+ throw new MessageException($"{i18N.Translate("Unhandled Exception")}\n{e.Message}");
}
-
- using var _ = await Lock.EnterAsync();
-
- if (ServerController == null && ModeController == null)
- return;
-
- Log.Information("Stop Main Controller");
- StatusPortInfoText.Reset();
-
- var tasks = new[]
- {
- ServerController?.StopAsync() ?? Task.CompletedTask,
- ModeController?.StopAsync() ?? Task.CompletedTask
- };
-
- try
- {
- await Task.WhenAll(tasks);
- }
- catch (Exception e)
- {
- Log.Error(e, "MainController Stop Error");
- }
-
- ServerController = null;
- ModeController = null;
- }
-
- public static void PortCheck(ushort port, string portName, PortType portType = PortType.Both)
- {
- try
- {
- PortHelper.CheckPort(port, portType);
- }
- catch (PortInUseException)
- {
- throw new MessageException(i18N.TranslateFormat("The {0} port is in use.", $"{portName} ({port})"));
- }
- catch (PortReservedException)
- {
- throw new MessageException(i18N.TranslateFormat("The {0} port is reserved by system.", $"{portName} ({port})"));
- }
- }
-
- public static void TryReleaseTcpPort(ushort port, string portName)
- {
- foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
- {
- var fileName = p.MainModule?.FileName;
- if (fileName == null)
- continue;
-
- if (fileName.StartsWith(Global.NetchDir))
- {
- p.Kill();
- p.WaitForExit();
- }
- else
- {
- throw new MessageException(i18N.TranslateFormat("The {0} port is used by {1}.", $"{portName} ({port})", $"({p.Id}){fileName}"));
- }
- }
-
- PortCheck(port, portName, PortType.TCP);
- }
-
- public static async Task DiscoveryNatTypeAsync(CancellationToken ctx = default)
- {
- Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
- return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
- }
-
- public static async Task HttpConnectAsync(CancellationToken ctx = default)
- {
- Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
- try
- {
- return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
- }
- catch (OperationCanceledException)
- {
- // ignored
- }
- catch (Exception e)
- {
- Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception");
- }
-
- return null;
}
}
+
+ public static async Task StopAsync()
+ {
+ if (Lock.CurrentCount == 0)
+ {
+ (await Lock.EnterAsync()).Dispose();
+ if (ServerController == null && ModeController == null)
+ // stopped
+ return;
+
+ // else begin stop
+ }
+
+ using var _ = await Lock.EnterAsync();
+
+ if (ServerController == null && ModeController == null)
+ return;
+
+ Log.Information("Stop Main Controller");
+ StatusPortInfoText.Reset();
+
+ var tasks = new[]
+ {
+ ServerController?.StopAsync() ?? Task.CompletedTask,
+ ModeController?.StopAsync() ?? Task.CompletedTask
+ };
+
+ try
+ {
+ await Task.WhenAll(tasks);
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "MainController Stop Error");
+ }
+
+ ServerController = null;
+ ModeController = null;
+ }
+
+ public static void PortCheck(ushort port, string portName, PortType portType = PortType.Both)
+ {
+ try
+ {
+ PortHelper.CheckPort(port, portType);
+ }
+ catch (PortInUseException)
+ {
+ throw new MessageException(i18N.TranslateFormat("The {0} port is in use.", $"{portName} ({port})"));
+ }
+ catch (PortReservedException)
+ {
+ throw new MessageException(i18N.TranslateFormat("The {0} port is reserved by system.", $"{portName} ({port})"));
+ }
+ }
+
+ public static void TryReleaseTcpPort(ushort port, string portName)
+ {
+ foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
+ {
+ var fileName = p.MainModule?.FileName;
+ if (fileName == null)
+ continue;
+
+ if (fileName.StartsWith(Global.NetchDir))
+ {
+ p.Kill();
+ p.WaitForExit();
+ }
+ else
+ {
+ throw new MessageException(i18N.TranslateFormat("The {0} port is used by {1}.", $"{portName} ({port})", $"({p.Id}){fileName}"));
+ }
+ }
+
+ PortCheck(port, portName, PortType.TCP);
+ }
+
+ public static async Task DiscoveryNatTypeAsync(CancellationToken ctx = default)
+ {
+ Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
+ return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
+ }
+
+ public static async Task HttpConnectAsync(CancellationToken ctx = default)
+ {
+ Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
+ try
+ {
+ return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
+ }
+ catch (OperationCanceledException)
+ {
+ // ignored
+ }
+ catch (Exception e)
+ {
+ Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception");
+ }
+
+ return null;
+ }
}
\ No newline at end of file
diff --git a/Netch/Controllers/NFController.cs b/Netch/Controllers/NFController.cs
index 82a02e6c..18399095 100644
--- a/Netch/Controllers/NFController.cs
+++ b/Netch/Controllers/NFController.cs
@@ -1,262 +1,255 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
+using System.Net;
using System.ServiceProcess;
-using System.Threading.Tasks;
using Netch.Interfaces;
using Netch.Models;
using Netch.Models.Modes;
using Netch.Models.Modes.ProcessMode;
using Netch.Servers;
using Netch.Utils;
-using Serilog;
using static Netch.Interops.Redirector;
-namespace Netch.Controllers
+namespace Netch.Controllers;
+
+public class NFController : IModeController
{
- public class NFController : IModeController
+ private Server? _server;
+ private Redirector _mode = null!;
+ private RedirectorConfig _rdrConfig = null!;
+
+ private static readonly ServiceController NFService = new("netfilter2");
+
+ private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
+
+ public string Name => "Redirector";
+
+ public ModeFeature Features => ModeFeature.SupportIPv6 | ModeFeature.SupportSocks5Auth;
+
+ public async Task StartAsync(Socks5Server server, Mode mode)
{
- private Server? _server;
- private Redirector _mode = null!;
- private RedirectorConfig _rdrConfig = null!;
+ if (mode is not Redirector processMode)
+ throw new InvalidOperationException();
- private static readonly ServiceController NFService = new("netfilter2");
+ _server = server;
+ _mode = processMode;
+ _rdrConfig = Global.Settings.Redirector;
- private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
+ CheckDriver();
- public string Name => "Redirector";
+ 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());
- public ModeFeature Features => ModeFeature.SupportIPv6 | ModeFeature.SupportSocks5Auth;
+ Dial(NameList.AIO_FILTERTCP, _mode.FilterTCP ?? _rdrConfig.FilterTCP);
+ Dial(NameList.AIO_FILTERUDP, _mode.FilterUDP ?? _rdrConfig.FilterUDP);
- public async Task StartAsync(Socks5Server server, Mode mode)
+ // 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)
{
- if (mode is not Redirector processMode)
- throw new InvalidOperationException();
+ var dnsStr = _mode.FilterDNS != null ? _mode.DNSHost : _rdrConfig.DNSHost;
- _server = server;
- _mode = processMode;
- _rdrConfig = Global.Settings.Redirector;
+ dnsStr = dnsStr.ValueOrDefault() ?? $"{Constants.DefaultPrimaryDNS}:53";
- CheckDriver();
+ var dns = IPEndPoint.Parse(dnsStr);
+ if (dns.Port == 0)
+ dns.Port = 53;
- 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}:53";
-
- 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_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();
-
- if (!await InitAsync())
- throw new MessageException("Redirector start failed.");
+ Dial(NameList.AIO_DNSHOST, dns.Address.ToString());
+ Dial(NameList.AIO_DNSPORT, dns.Port.ToString());
}
- public async Task StopAsync()
- {
- await FreeAsync();
- }
+ // Server
+ 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);
- #region CheckRule
+ // Mode Rule
+ DialRule();
- ///
- ///
- ///
- ///
- /// No Problem true
- private static bool CheckCppRegex(string r, bool clear = true)
- {
- try
- {
- if (r.StartsWith("!"))
- return Dial(NameList.AIO_ADDNAME, r.Substring(1));
-
- return Dial(NameList.AIO_ADDNAME, r);
- }
- finally
- {
- if (clear)
- Dial(NameList.AIO_CLRNAME, "");
- }
- }
-
- ///
- ///
- ///
- ///
- /// No Problem true
- public static bool CheckRules(IEnumerable rules, out IEnumerable results)
- {
- results = rules.Where(r => !CheckCppRegex(r, false));
- Dial(NameList.AIO_CLRNAME, "");
- return !results.Any();
- }
-
- public static string GenerateInvalidRulesMessage(IEnumerable rules)
- {
- return $"{string.Join("\n", rules)}\n" + i18N.Translate("Above rules does not conform to C++ regular expression syntax");
- }
-
- #endregion
-
- private void DialRule()
- {
- Dial(NameList.AIO_CLRNAME, "");
- var invalidList = new List();
- foreach (var s in _mode.Bypass)
- {
- if (!Dial(NameList.AIO_BYPNAME, s))
- invalidList.Add(s);
- }
-
- foreach (var s in _mode.Handle)
- {
- if (!Dial(NameList.AIO_ADDNAME, s))
- invalidList.Add(s);
- }
-
- if (invalidList.Any())
- throw new MessageException(GenerateInvalidRulesMessage(invalidList));
-
- // Bypass Self
- Dial(NameList.AIO_BYPNAME, "^" + Global.NetchDir.ToRegexString());
- }
-
- #region DriverUtil
-
- private static void CheckDriver()
- {
- var binFileVersion = Utils.Utils.GetFileVersion(Constants.NFDriver);
- var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
-
- Log.Information("Built-in netfilter2 driver version: {Name}", binFileVersion);
- Log.Information("Installed netfilter2 driver version: {Name}", systemFileVersion);
-
- if (!File.Exists(SystemDriver))
- {
- // Install
- InstallDriver();
- return;
- }
-
- var reinstall = false;
- if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
- {
- if (binResult.CompareTo(systemResult) > 0)
- // Update
- reinstall = true;
- else if (systemResult.Major != binResult.Major)
- // Downgrade when Major version different (may have breaking changes)
- reinstall = true;
- }
- else
- {
- // Parse File versionName to Version failed
- if (!systemFileVersion.Equals(binFileVersion))
- // versionNames are different, Reinstall
- reinstall = true;
- }
-
- if (!reinstall)
- return;
-
- Log.Information("Update netfilter2 driver");
- UninstallDriver();
- InstallDriver();
- }
-
- ///
- /// 安装 NF 驱动
- ///
- /// 驱动是否安装成功
- private static void InstallDriver()
- {
- Log.Information("Install netfilter2 driver");
- Global.MainForm.StatusText(i18N.Translate("Installing netfilter2 driver"));
-
- if (!File.Exists(Constants.NFDriver))
- throw new MessageException(i18N.Translate("builtin driver files missing, can't install NF driver"));
-
- try
- {
- File.Copy(Constants.NFDriver, SystemDriver);
- }
- catch (Exception e)
- {
- Log.Error(e, "Copy netfilter2.sys failed\n");
- throw new MessageException($"Copy netfilter2.sys failed\n{e.Message}");
- }
-
- // 注册驱动文件
- if (Interops.Redirector.aio_register("netfilter2"))
- {
- Log.Information("Install netfilter2 driver finished");
- }
- else
- {
- Log.Error("Register netfilter2 failed");
- }
- }
-
- ///
- /// 卸载 NF 驱动
- ///
- /// 是否成功卸载
- public static bool UninstallDriver()
- {
- Log.Information("Uninstall netfilter2");
- try
- {
- if (NFService.Status == ServiceControllerStatus.Running)
- {
- NFService.Stop();
- NFService.WaitForStatus(ServiceControllerStatus.Stopped);
- }
- }
- catch (Exception)
- {
- // ignored
- }
-
- if (!File.Exists(SystemDriver))
- return true;
-
- Interops.Redirector.aio_unregister("netfilter2");
- File.Delete(SystemDriver);
-
- return true;
- }
-
- #endregion
+ if (!await InitAsync())
+ throw new MessageException("Redirector start failed.");
}
+
+ public async Task StopAsync()
+ {
+ await FreeAsync();
+ }
+
+ #region CheckRule
+
+ ///
+ ///
+ ///
+ ///
+ /// No Problem true
+ private static bool CheckCppRegex(string r, bool clear = true)
+ {
+ try
+ {
+ if (r.StartsWith("!"))
+ return Dial(NameList.AIO_ADDNAME, r.Substring(1));
+
+ return Dial(NameList.AIO_ADDNAME, r);
+ }
+ finally
+ {
+ if (clear)
+ Dial(NameList.AIO_CLRNAME, "");
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// No Problem true
+ public static bool CheckRules(IEnumerable rules, out IEnumerable results)
+ {
+ results = rules.Where(r => !CheckCppRegex(r, false));
+ Dial(NameList.AIO_CLRNAME, "");
+ return !results.Any();
+ }
+
+ public static string GenerateInvalidRulesMessage(IEnumerable rules)
+ {
+ return $"{string.Join("\n", rules)}\n" + i18N.Translate("Above rules does not conform to C++ regular expression syntax");
+ }
+
+ #endregion
+
+ private void DialRule()
+ {
+ Dial(NameList.AIO_CLRNAME, "");
+ var invalidList = new List();
+ foreach (var s in _mode.Bypass)
+ {
+ if (!Dial(NameList.AIO_BYPNAME, s))
+ invalidList.Add(s);
+ }
+
+ foreach (var s in _mode.Handle)
+ {
+ if (!Dial(NameList.AIO_ADDNAME, s))
+ invalidList.Add(s);
+ }
+
+ if (invalidList.Any())
+ throw new MessageException(GenerateInvalidRulesMessage(invalidList));
+
+ // Bypass Self
+ Dial(NameList.AIO_BYPNAME, "^" + Global.NetchDir.ToRegexString());
+ }
+
+ #region DriverUtil
+
+ private static void CheckDriver()
+ {
+ var binFileVersion = Utils.Utils.GetFileVersion(Constants.NFDriver);
+ var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
+
+ Log.Information("Built-in netfilter2 driver version: {Name}", binFileVersion);
+ Log.Information("Installed netfilter2 driver version: {Name}", systemFileVersion);
+
+ if (!File.Exists(SystemDriver))
+ {
+ // Install
+ InstallDriver();
+ return;
+ }
+
+ var reinstall = false;
+ if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
+ {
+ if (binResult.CompareTo(systemResult) > 0)
+ // Update
+ reinstall = true;
+ else if (systemResult.Major != binResult.Major)
+ // Downgrade when Major version different (may have breaking changes)
+ reinstall = true;
+ }
+ else
+ {
+ // Parse File versionName to Version failed
+ if (!systemFileVersion.Equals(binFileVersion))
+ // versionNames are different, Reinstall
+ reinstall = true;
+ }
+
+ if (!reinstall)
+ return;
+
+ Log.Information("Update netfilter2 driver");
+ UninstallDriver();
+ InstallDriver();
+ }
+
+ ///
+ /// 安装 NF 驱动
+ ///
+ /// 驱动是否安装成功
+ private static void InstallDriver()
+ {
+ Log.Information("Install netfilter2 driver");
+ Global.MainForm.StatusText(i18N.Translate("Installing netfilter2 driver"));
+
+ if (!File.Exists(Constants.NFDriver))
+ throw new MessageException(i18N.Translate("builtin driver files missing, can't install NF driver"));
+
+ try
+ {
+ File.Copy(Constants.NFDriver, SystemDriver);
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Copy netfilter2.sys failed\n");
+ throw new MessageException($"Copy netfilter2.sys failed\n{e.Message}");
+ }
+
+ // 注册驱动文件
+ if (Interops.Redirector.aio_register("netfilter2"))
+ {
+ Log.Information("Install netfilter2 driver finished");
+ }
+ else
+ {
+ Log.Error("Register netfilter2 failed");
+ }
+ }
+
+ ///
+ /// 卸载 NF 驱动
+ ///
+ /// 是否成功卸载
+ public static bool UninstallDriver()
+ {
+ Log.Information("Uninstall netfilter2");
+ try
+ {
+ if (NFService.Status == ServiceControllerStatus.Running)
+ {
+ NFService.Stop();
+ NFService.WaitForStatus(ServiceControllerStatus.Stopped);
+ }
+ }
+ catch (Exception)
+ {
+ // ignored
+ }
+
+ if (!File.Exists(SystemDriver))
+ return true;
+
+ Interops.Redirector.aio_unregister("netfilter2");
+ File.Delete(SystemDriver);
+
+ return true;
+ }
+
+ #endregion
}
\ No newline at end of file
diff --git a/Netch/Controllers/PcapController.cs b/Netch/Controllers/PcapController.cs
index ae1c28f2..e5338b67 100644
--- a/Netch/Controllers/PcapController.cs
+++ b/Netch/Controllers/PcapController.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Text;
using Microsoft.VisualStudio.Threading;
using Netch.Forms;
using Netch.Interfaces;
@@ -13,93 +8,92 @@ using Netch.Models.Modes.ShareMode;
using Netch.Servers;
using Netch.Utils;
-namespace Netch.Controllers
+namespace Netch.Controllers;
+
+public class PcapController : Guard, IModeController
{
- public class PcapController : Guard, IModeController
+ private readonly LogForm _form;
+ private ShareMode _mode = null!;
+ private Socks5Server _server = null!;
+
+ public PcapController() : base("pcap2socks.exe", encoding: Encoding.UTF8)
{
- private readonly LogForm _form;
- private ShareMode _mode = null!;
- private Socks5Server _server = null!;
+ _form = new LogForm(Global.MainForm);
+ _form.CreateControl();
+ }
- public PcapController() : base("pcap2socks.exe", encoding: Encoding.UTF8)
+ protected override IEnumerable StartedKeywords { get; } = new[] { "└" };
+
+ 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 = shareMode;
+
+ var outboundNetworkInterface = NetworkInterfaceUtils.GetBest();
+
+ var arguments = new List