diff --git a/Netch/Controllers/DNSController.cs b/Netch/Controllers/DNSController.cs index 835d1714..010b592f 100644 --- a/Netch/Controllers/DNSController.cs +++ b/Netch/Controllers/DNSController.cs @@ -15,7 +15,7 @@ namespace Netch.Controllers await FreeAsync(); } - public void Start() + public async Task StartAsync() { MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS"); @@ -28,7 +28,7 @@ namespace Netch.Controllers Dial(NameList.TYPE_CDNS, $"{aioDnsConfig.ChinaDNS}"); Dial(NameList.TYPE_ODNS, $"{aioDnsConfig.OtherDNS}"); - if (!Init()) + if (!await InitAsync()) throw new Exception("AioDNS start failed."); } } diff --git a/Netch/Controllers/Guard.cs b/Netch/Controllers/Guard.cs index f86022a5..0640c1c1 100644 --- a/Netch/Controllers/Guard.cs +++ b/Netch/Controllers/Guard.cs @@ -71,7 +71,7 @@ namespace Netch.Controllers { State = State.Starting; - _logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read); + _logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read); _logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true }; Instance.StartInfo.Arguments = argument; diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 35745343..50edfffa 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -62,6 +62,7 @@ namespace Netch.Controllers 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}"); } } diff --git a/Netch/Controllers/NTTController.cs b/Netch/Controllers/NTTController.cs index 5a093f35..b03e7828 100644 --- a/Netch/Controllers/NTTController.cs +++ b/Netch/Controllers/NTTController.cs @@ -42,12 +42,17 @@ namespace Netch.Controllers } if (output.IsNullOrWhiteSpace()) - if (!error.IsNullOrWhiteSpace()) + { + if (error.IsNullOrWhiteSpace()) { - var errorFirst = error.GetLines().First(); - return (errorFirst.SplitTrimEntries(':').Last(), null, null); + Log.Warning("NTT no output"); + return (null, null, null); } + var errorFirst = error.GetLines().First(); + return (errorFirst.SplitTrimEntries(':').Last(), null, null); + } + foreach (var line in output.Split('\n')) { var str = line.SplitTrimEntries(':'); diff --git a/Netch/Controllers/PcapController.cs b/Netch/Controllers/PcapController.cs index ec6f1239..f0fb2197 100644 --- a/Netch/Controllers/PcapController.cs +++ b/Netch/Controllers/PcapController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -38,10 +39,10 @@ namespace Netch.Controllers var outboundNetworkInterface = NetworkInterfaceUtils.GetBest(); var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.Id}"); - if (_server is Socks5 socks5 && !socks5.Auth()) + if (_server is Socks5Bridge socks5) argument.Append($" --destination {await socks5.AutoResolveHostnameAsync()}:{socks5.Port}"); else - argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}"); + Trace.Assert(false); argument.Append($" {_mode.GetRules().FirstOrDefault() ?? "-P n"}"); await StartGuardAsync(argument.ToString()); @@ -77,10 +78,11 @@ namespace Netch.Controllers if (new FileInfo(LogPath).Length == 0) { Task.Run(() => - { - Thread.Sleep(1000); - Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies"); - }).Forget(); + { + Thread.Sleep(1000); + Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies"); + }) + .Forget(); throw new MessageException("Pleases install pcap2socks's dependency"); } diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index 9e7c87fe..7b91ec04 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -86,7 +86,7 @@ namespace Netch.Controllers } else { - _aioDnsController.Start(); + await _aioDnsController.StartAsync(); Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}"); } diff --git a/Netch/Controllers/UpdateChecker.cs b/Netch/Controllers/UpdateChecker.cs index faf583f8..6aba0ff1 100644 --- a/Netch/Controllers/UpdateChecker.cs +++ b/Netch/Controllers/UpdateChecker.cs @@ -67,7 +67,7 @@ namespace Netch.Controllers else Log.Error(e, "获取新版本异常"); - NewVersionFoundFailed?.Invoke(null, new EventArgs()); + NewVersionFoundFailed?.Invoke(null, EventArgs.Empty); } } diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index 9ace3b8c..583a7364 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -53,7 +53,8 @@ namespace Netch.Forms private void AddAddServerToolStripMenuItems() { - foreach (var serversUtil in ServerHelper.ServerUtils.Where(i => !string.IsNullOrEmpty(i.FullName))) + foreach (var serversUtil in ServerHelper.ServerUtilDictionary.Values.OrderBy(i => i.Priority) + .Where(i => !string.IsNullOrEmpty(i.FullName))) { var fullName = serversUtil.FullName; var control = new ToolStripMenuItem @@ -636,9 +637,6 @@ namespace Netch.Forms return; } - if (!server.Valid()) - return; - Hide(); ServerHelper.GetUtilByTypeName(server.Type).Edit(server); LoadServers(); @@ -679,9 +677,6 @@ namespace Netch.Forms return; } - if (!server.Valid()) - return; - try { //听说巨硬BUG经常会炸,所以Catch一下 :D diff --git a/Netch/Interops/AioDNS.cs b/Netch/Interops/AioDNS.cs index a81368db..d0867937 100644 --- a/Netch/Interops/AioDNS.cs +++ b/Netch/Interops/AioDNS.cs @@ -15,6 +15,11 @@ namespace Netch.Interops return aiodns_dial(name, Encoding.UTF8.GetBytes(value)); } + public static async Task InitAsync() + { + return await Task.Run(Init).ConfigureAwait(false); + } + public static async Task FreeAsync() { await Task.Run(Free).ConfigureAwait(false); diff --git a/Netch/Models/Server.cs b/Netch/Models/Server.cs index fd793b7c..f9307bba 100644 --- a/Netch/Models/Server.cs +++ b/Netch/Models/Server.cs @@ -118,19 +118,6 @@ namespace Netch.Models return Global.Settings.ResolveServerHostname ? (await DnsUtils.LookupAsync(server.Hostname))!.ToString() : server.Hostname; } - public static bool Valid(this Server server) - { - try - { - ServerHelper.GetTypeByTypeName(server.Type); - return true; - } - catch - { - return false; - } - } - public static bool IsInGroup(this Server server) { return server.Group is not Constants.DefaultGroup; diff --git a/Netch/Netch.cs b/Netch/Netch.cs index 29ac49d5..1363411b 100644 --- a/Netch/Netch.cs +++ b/Netch/Netch.cs @@ -51,7 +51,9 @@ namespace Netch Directory.CreateDirectory(item); // 加载配置 +#pragma warning disable VSTHRD002 Configuration.LoadAsync().Wait(); +#pragma warning restore VSTHRD002 if (!SingleInstance.IsFirstInstance) { diff --git a/Netch/Utils/Bandwidth.cs b/Netch/Utils/Bandwidth.cs index 2d708c75..347f8ef4 100644 --- a/Netch/Utils/Bandwidth.cs +++ b/Netch/Utils/Bandwidth.cs @@ -53,69 +53,68 @@ namespace Netch.Utils var counterLock = new object(); //int sent = 0; - //var processList = Process.GetProcessesByName(ProcessName).Select(p => p.Id).ToHashSet(); - var instances = new List(); + var processes = new List(); switch (MainController.ServerController) { case null: break; case Guard guard: - instances.Add(guard.Instance); - + processes.Add(guard.Instance); break; } - if (!instances.Any()) + if (!processes.Any()) switch (MainController.ModeController) { case null: break; - case NFController: - instances.Add(Process.GetCurrentProcess()); + case NFController or TUNController: + processes.Add(Process.GetCurrentProcess()); break; case Guard guard: - instances.Add(guard.Instance); + processes.Add(guard.Instance); break; } - var processList = instances.Select(instance => instance.Id).ToHashSet(); + var pidHastSet = processes.Select(instance => instance.Id).ToHashSet(); - Log.Information("流量统计进程: {Processes}", string.Join(',', instances.Select(v => $"({v.Id}){v.ProcessName}"))); + Log.Information("流量统计进程: {Processes}", string.Join(',', processes.Select(v => $"({v.Id}){v.ProcessName}"))); received = 0; - if (!instances.Any()) + if (!processes.Any()) return; Global.MainForm.BandwidthState(true); Task.Run(() => - { - tSession = new TraceEventSession("KernelAndClrEventsSession"); - tSession.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP); - - //这玩意儿上传和下载得到的data是一样的:) - //所以暂时没办法区分上传下载流量 - tSession.Source.Kernel.TcpIpRecv += data => { - if (processList.Contains(data.ProcessID)) - lock (counterLock) - received += (ulong)data.size; + tSession = new TraceEventSession("KernelAndClrEventsSession"); + tSession.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP); - // Debug.WriteLine($"TcpIpRecv: {ToByteSize(data.size)}"); - }; + //这玩意儿上传和下载得到的data是一样的:) + //所以暂时没办法区分上传下载流量 + tSession.Source.Kernel.TcpIpRecv += data => + { + if (pidHastSet.Contains(data.ProcessID)) + lock (counterLock) + received += (ulong)data.size; - tSession.Source.Kernel.UdpIpRecv += data => - { - if (processList.Contains(data.ProcessID)) - lock (counterLock) - received += (ulong)data.size; + // Debug.WriteLine($"TcpIpRecv: {ToByteSize(data.size)}"); + }; - // Debug.WriteLine($"UdpIpRecv: {ToByteSize(data.size)}"); - }; + tSession.Source.Kernel.UdpIpRecv += data => + { + if (pidHastSet.Contains(data.ProcessID)) + lock (counterLock) + received += (ulong)data.size; - tSession.Source.Process(); - }).Forget(); + // Debug.WriteLine($"UdpIpRecv: {ToByteSize(data.size)}"); + }; + + tSession.Source.Process(); + }) + .Forget(); while (Global.MainForm.State != State.Stopped) { diff --git a/Netch/Utils/Configuration.cs b/Netch/Utils/Configuration.cs index 00395551..828dace9 100644 --- a/Netch/Utils/Configuration.cs +++ b/Netch/Utils/Configuration.cs @@ -45,6 +45,8 @@ namespace Netch.Utils return; } + await using var _ = await _lock.ReadLockAsync(); + if (await LoadCoreAsync(FileFullName)) return; diff --git a/Netch/Utils/DnsUtils.cs b/Netch/Utils/DnsUtils.cs index 8357bf05..62eebb6d 100644 --- a/Netch/Utils/DnsUtils.cs +++ b/Netch/Utils/DnsUtils.cs @@ -1,8 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Net; +using System.Net.Sockets; using System.Threading.Tasks; using Serilog; @@ -14,13 +16,23 @@ namespace Netch.Utils /// 缓存 /// private static readonly Hashtable Cache = new(); + private static readonly Hashtable Cache6 = new(); - public static async Task LookupAsync(string hostname, int timeout = 3000) + public static async Task LookupAsync(string hostname, AddressFamily inet = AddressFamily.InterNetwork, int timeout = 3000) { try { - if (Cache.Contains(hostname)) - return Cache[hostname] as IPAddress; + if (inet == AddressFamily.InterNetwork) + { + if (Cache.Contains(hostname)) + return Cache[hostname] as IPAddress; + } + else + { + Trace.Assert(inet == AddressFamily.InterNetworkV6); + if (Cache6.Contains(hostname)) + return Cache6[hostname] as IPAddress; + } var task = Dns.GetHostAddressesAsync(hostname); @@ -28,14 +40,18 @@ namespace Netch.Utils if (resTask == task) { - var result = await task; + var addresses = await task; - if (result.Length == 0) + var result = addresses.FirstOrDefault(i => i.AddressFamily == inet); + if (result == null) return null; - Cache.Add(hostname, result[0]); + if (inet == AddressFamily.InterNetwork) + Cache.Add(hostname, result); + else + Cache6.Add(hostname, result); - return result[0]; + return result; } return null; @@ -55,6 +71,7 @@ namespace Netch.Utils public static void ClearCache() { Cache.Clear(); + Cache6.Clear(); } public static IEnumerable Split(string dns) diff --git a/Netch/Utils/NetworkInterfaceUtils.cs b/Netch/Utils/NetworkInterfaceUtils.cs index ee12b60a..2ba56214 100644 --- a/Netch/Utils/NetworkInterfaceUtils.cs +++ b/Netch/Utils/NetworkInterfaceUtils.cs @@ -14,12 +14,16 @@ namespace Netch.Utils { public static NetworkInterface GetBest(AddressFamily addressFamily = AddressFamily.InterNetwork) { - var ipAddress = addressFamily switch + string ipAddress; + if (addressFamily == AddressFamily.InterNetwork) { - AddressFamily.InterNetwork => "114.114.114.114", - AddressFamily.InterNetworkV6 => throw new NotImplementedException(), - _ => throw new ArgumentOutOfRangeException(nameof(addressFamily), addressFamily, null) - }; + ipAddress = "114.114.114.114"; + } + else + { + Trace.Assert(addressFamily == AddressFamily.InterNetworkV6); + throw new NotImplementedException(); + } if (PInvoke.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0), 0, out var route) != 0) throw new MessageException("GetBestRoute 搜索失败"); diff --git a/Netch/Utils/PortHelper.cs b/Netch/Utils/PortHelper.cs index bfb021ae..d062775e 100644 --- a/Netch/Utils/PortHelper.cs +++ b/Netch/Utils/PortHelper.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Net.NetworkInformation; +using System.Net.Sockets; using System.Runtime.InteropServices; using Windows.Win32; using Windows.Win32.NetworkManagement.IpHelper; @@ -31,13 +32,13 @@ namespace Netch.Utils } } - internal static IEnumerable GetProcessByUsedTcpPort(ushort port, ADDRESS_FAMILY inet = ADDRESS_FAMILY.AF_INET) + internal static IEnumerable GetProcessByUsedTcpPort(ushort port, AddressFamily inet = AddressFamily.InterNetwork) { if (port == 0) throw new ArgumentOutOfRangeException(); - if (inet is ADDRESS_FAMILY.AF_UNSPEC) - throw new ArgumentOutOfRangeException(nameof(inet)); + if (inet != AddressFamily.InterNetwork) + Trace.Assert(inet == AddressFamily.InterNetworkV6); var process = new List(); unsafe @@ -50,9 +51,9 @@ namespace Netch.Utils 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++) + for (var i = 0; i < tcpTable -> dwNumEntries; i++) { - var row = tcpTable->table.ReadOnlyItemRef(i); + var row = tcpTable -> table.ReadOnlyItemRef(i); if (row.dwOwningPid is 0 or 4) continue; diff --git a/Netch/Utils/ServerConverterWithTypeDiscriminator.cs b/Netch/Utils/ServerConverterWithTypeDiscriminator.cs index ef48024a..8c9f755f 100644 --- a/Netch/Utils/ServerConverterWithTypeDiscriminator.cs +++ b/Netch/Utils/ServerConverterWithTypeDiscriminator.cs @@ -16,6 +16,7 @@ namespace Netch.Utils try { var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!); + // TODO replace with .NET 6 Deserialize from DOM return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!; } catch diff --git a/Netch/Utils/ServerHelper.cs b/Netch/Utils/ServerHelper.cs index be93f1cf..7b94d7be 100644 --- a/Netch/Utils/ServerHelper.cs +++ b/Netch/Utils/ServerHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading; @@ -19,12 +20,7 @@ namespace Netch.Utils .GetExportedTypes() .Where(type => type.GetInterfaces().Contains(typeof(IServerUtil))); - ServerUtils = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).OrderBy(util => util.Priority); - } - - public static Type GetTypeByTypeName(string typeName) - { - return ServerUtils.Single(i => i.TypeName.Equals(typeName)).ServerType; + ServerUtilDictionary = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).ToDictionary(util => util.TypeName); } #region Delay @@ -118,27 +114,21 @@ namespace Netch.Utils #region Handler - public static readonly IEnumerable ServerUtils; + public static Dictionary ServerUtilDictionary { get; set; } public static IServerUtil GetUtilByTypeName(string typeName) { - if (string.IsNullOrEmpty(typeName)) - throw new ArgumentNullException(); - - return ServerUtils.Single(i => i.TypeName.Equals(typeName)); + return ServerUtilDictionary[typeName]; } - public static IServerUtil GetUtilByFullName(string fullName) + public static IServerUtil? GetUtilByUriScheme(string scheme) { - if (string.IsNullOrEmpty(fullName)) - throw new ArgumentNullException(); - - return ServerUtils.Single(i => i.FullName.Equals(fullName)); + return ServerUtilDictionary.Values.SingleOrDefault(i => i.UriScheme.Any(s => s.Equals(scheme))); } - public static IServerUtil? GetUtilByUriScheme(string typeName) + public static Type GetTypeByTypeName(string typeName) { - return ServerUtils.SingleOrDefault(i => i.UriScheme.Any(s => s.Equals(typeName))); + return GetUtilByTypeName(typeName).ServerType; } #endregion diff --git a/Netch/Utils/StringExtension.cs b/Netch/Utils/StringExtension.cs index 0362c673..0ed59a2c 100644 --- a/Netch/Utils/StringExtension.cs +++ b/Netch/Utils/StringExtension.cs @@ -73,9 +73,9 @@ namespace Netch.Utils return value.Split(separator, StringSplitOptions.RemoveEmptyEntries); } - public static string? ValueOrDefault(this string? value) + public static string? ValueOrDefault(this string? value, string? defaultValue = default) { - return string.IsNullOrWhiteSpace(value) ? null : value; + return string.IsNullOrWhiteSpace(value) ? defaultValue : value; } public static string[]? SplitOrDefault(this string? value)