mirror of
https://github.com/netchx/netch.git
synced 2026-05-07 22:44:03 +08:00
Refactors
This commit is contained in:
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(':');
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Netch.Controllers
|
||||
else
|
||||
Log.Error(e, "获取新版本异常");
|
||||
|
||||
NewVersionFoundFailed?.Invoke(null, new EventArgs());
|
||||
NewVersionFoundFailed?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,6 +15,11 @@ namespace Netch.Interops
|
||||
return aiodns_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public static async Task<bool> InitAsync()
|
||||
{
|
||||
return await Task.Run(Init).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task FreeAsync()
|
||||
{
|
||||
await Task.Run(Free).ConfigureAwait(false);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace Netch
|
||||
Directory.CreateDirectory(item);
|
||||
|
||||
// 加载配置
|
||||
#pragma warning disable VSTHRD002
|
||||
Configuration.LoadAsync().Wait();
|
||||
#pragma warning restore VSTHRD002
|
||||
|
||||
if (!SingleInstance.IsFirstInstance)
|
||||
{
|
||||
|
||||
@@ -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<Process>();
|
||||
var processes = new List<Process>();
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace Netch.Utils
|
||||
return;
|
||||
}
|
||||
|
||||
await using var _ = await _lock.ReadLockAsync();
|
||||
|
||||
if (await LoadCoreAsync(FileFullName))
|
||||
return;
|
||||
|
||||
|
||||
@@ -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
|
||||
/// 缓存
|
||||
/// </summary>
|
||||
private static readonly Hashtable Cache = new();
|
||||
private static readonly Hashtable Cache6 = new();
|
||||
|
||||
public static async Task<IPAddress?> LookupAsync(string hostname, int timeout = 3000)
|
||||
public static async Task<IPAddress?> 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<string> Split(string dns)
|
||||
|
||||
@@ -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 搜索失败");
|
||||
|
||||
@@ -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<Process> GetProcessByUsedTcpPort(ushort port, ADDRESS_FAMILY inet = ADDRESS_FAMILY.AF_INET)
|
||||
internal static IEnumerable<Process> 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<Process>();
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<IServerUtil> ServerUtils;
|
||||
public static Dictionary<string, IServerUtil> 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user