From 0714a7bc127eaec1d26fd959fe4f72d78d4bfc98 Mon Sep 17 00:00:00 2001 From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com> Date: Wed, 3 Mar 2021 19:37:04 +0800 Subject: [PATCH] Refactor Get NetworkInterfaces --- Netch/Controllers/MainController.cs | 12 +-- Netch/Controllers/NFController.cs | 16 +-- Netch/Controllers/TUNTAPController.cs | 149 ++++++++------------------ Netch/Global.cs | 50 --------- Netch/Models/IAdapter.cs | 15 +++ Netch/Models/OutboundAdapter.cs | 69 ++++++++++++ Netch/Models/TapAdapter.cs | 30 ++++++ Netch/Utils/DNS.cs | 31 ------ Netch/Utils/TUNTAP.cs | 48 +++++---- Netch/Utils/Utils.cs | 35 ------ 10 files changed, 195 insertions(+), 260 deletions(-) create mode 100644 Netch/Models/IAdapter.cs create mode 100644 Netch/Models/OutboundAdapter.cs create mode 100644 Netch/Models/TapAdapter.cs diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 9658ac20..b94b2136 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Net; using System.Threading; using System.Threading.Tasks; using Netch.Models; @@ -62,16 +61,7 @@ namespace Netch.Controllers // 刷新DNS缓存 NativeMethods.FlushDNSResolverCache(); - try - { - WebUtil.BestLocalEndPoint(new IPEndPoint(0x72727272, 53)); - } - catch (Exception) - { - throw new MessageException(i18N.Translate("No internet connection")); - } - - if (Global.Settings.ResolveServerHostname && DNS.Lookup(server.Hostname) == null) + if (DNS.Lookup(server.Hostname) == null) throw new MessageException(i18N.Translate("Lookup Server hostname failed")); // 添加Netch到防火墙 diff --git a/Netch/Controllers/NFController.cs b/Netch/Controllers/NFController.cs index 6273c469..6089cf83 100644 --- a/Netch/Controllers/NFController.cs +++ b/Netch/Controllers/NFController.cs @@ -18,9 +18,11 @@ namespace Netch.Controllers { private static readonly ServiceController NFService = new("netfilter2"); - private static readonly string BinDriver = string.Empty; + private static readonly string BinDriver; private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys"; - private static string _sysDns = string.Empty; + + private static string? _sysDns; + private OutboundAdapter? _outbound; static NFController() { @@ -39,8 +41,7 @@ namespace Netch.Controllers fileName = "Win-7.sys"; break; default: - Logging.Error($"不支持的系统版本:{Environment.OSVersion.Version}"); - return; + throw new MessageException($"不支持的系统版本:{Environment.OSVersion.Version}"); } BinDriver = "bin\\" + fileName; @@ -93,12 +94,13 @@ namespace Netch.Controllers if (Global.Settings.ModifySystemDNS) { + _outbound = new OutboundAdapter(); // 备份并替换系统 DNS - _sysDns = DNS.OutboundDNS; + _sysDns = _outbound.DNS; if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS)) Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8"; - DNS.OutboundDNS = Global.Settings.ModifiedDNS; + _outbound.DNS = Global.Settings.ModifiedDNS; } if (!aio_init()) @@ -111,7 +113,7 @@ namespace Netch.Controllers { if (Global.Settings.ModifySystemDNS) //恢复系统DNS - DNS.OutboundDNS = _sysDns; + _outbound!.DNS = _sysDns!; }); aio_free(); diff --git a/Netch/Controllers/TUNTAPController.cs b/Netch/Controllers/TUNTAPController.cs index b960f18b..b88499a5 100644 --- a/Netch/Controllers/TUNTAPController.cs +++ b/Netch/Controllers/TUNTAPController.cs @@ -3,9 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; -using System.Net.NetworkInformation; using System.Text; -using System.Threading; using System.Threading.Tasks; using Netch.Models; using Netch.Servers.Socks5; @@ -21,7 +19,7 @@ namespace Netch.Controllers /// /// 服务器 IP 地址 /// - private IPAddress? _serverAddresses; + private IPAddress _serverAddresses = null!; /// /// 本地 DNS 服务控制器 @@ -38,47 +36,35 @@ namespace Netch.Controllers public override string Name { get; } = "tun2socks"; + private readonly OutboundAdapter _outbound = new(); + private TapAdapter _tap = null!; + public void Start(in Mode mode) { var server = MainController.Server!; - // 查询服务器 IP 地址 - _serverAddresses = DNS.Lookup(server.Hostname)!; + _serverAddresses = DNS.Lookup(server.Hostname)!; // server address have been cached when MainController.Start - // 查找出口适配器 - Utils.Utils.SearchOutboundAdapter(); + if (TUNTAP.GetComponentID() == null) + TUNTAP.AddTap(); - // 查找并安装 TAP 适配器 - if (string.IsNullOrEmpty(TUNTAP.GetComponentID())) - AddTap(); + _tap = new TapAdapter(); - SearchTapAdapter(); - - SetupRouteTable(mode); - - Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", Name)); - - string dns; + List dns; if (Global.Settings.TUNTAP.UseCustomDNS) { - if (Global.Settings.TUNTAP.DNS.Any()) - { - dns = DNS.Join(Global.Settings.TUNTAP.DNS); - } - else - { - Global.Settings.TUNTAP.DNS.Add("1.1.1.1"); - dns = "1.1.1.1"; - } + dns = Global.Settings.TUNTAP.DNS.Any() ? Global.Settings.TUNTAP.DNS : Global.Settings.TUNTAP.DNS = new List {"1.1.1.1"}; } else { MainController.PortCheck(53, "DNS"); - DNSController.Start(); - - dns = "127.0.0.1"; + dns = new List {"127.0.0.1"}; } + SetupRouteTable(mode); + + Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", Name)); + var argument = new StringBuilder(); if (server is Socks5 socks5 && !socks5.Auth()) argument.Append($"-proxyServer {server.AutoResolveHostname()}:{server.Port} "); @@ -86,7 +72,7 @@ namespace Netch.Controllers argument.Append($"-proxyServer 127.0.0.1:{Global.Settings.Socks5LocalPort} "); argument.Append( - $"-tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {dns} -tunName \"{TUNTAP.GetName(Global.TUNTAP.ComponentID)}\" "); + $"-tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {DNS.Join(dns)} -tunName \"{TUNTAP.GetName(_tap.ComponentID)}\" "); if (Global.Settings.TUNTAP.UseFakeDNS && Global.Flags.SupportFakeDns) argument.Append("-fakeDns "); @@ -164,7 +150,7 @@ namespace Netch.Controllers Process.Start(new ProcessStartInfo { FileName = "netsh", - Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0", + Arguments = $"interface ip set interface {_tap.Index} metric=0", WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = true, CreateNoWindow = true @@ -218,45 +204,6 @@ namespace Netch.Controllers } } - /// - /// 搜索出口和TUNTAP适配器 - /// - public static void SearchTapAdapter() - { - Global.TUNTAP.Adapter = null; - Global.TUNTAP.Index = -1; - Global.TUNTAP.ComponentID = TUNTAP.GetComponentID(); - - // 搜索 TUN/TAP 适配器的索引 - if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID)) - { - const string s = "TAP 适配器未安装"; - Logging.Info(s); - throw new Exception(s); - } - - // 根据 ComponentID 寻找 Tap适配器 - var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ => _.Id == Global.TUNTAP.ComponentID); - Global.TUNTAP.Adapter = adapter; - Global.TUNTAP.Index = adapter.GetIPProperties().GetIPv4Properties().Index; - Logging.Info($"TAP 适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.TUNTAP.Index}"); - } - - private static bool AddTap() - { - TUNTAP.addtap(); - // 给点时间,不然立马安装完毕就查找适配器可能会导致找不到适配器ID - Thread.Sleep(1000); - if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID = TUNTAP.GetComponentID())) - { - const string s = "TAP 驱动安装失败,找不到 ComponentID 注册表项"; - Logging.Error(s); - throw new Exception(s); - } - - return true; - } - private void RouteAction(Action action, in IEnumerable ipNetworks, RouteType routeType, int metric = 0) { foreach (var address in ipNetworks) @@ -265,54 +212,42 @@ namespace Netch.Controllers private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0) { - string gateway; - int index; - switch (routeType) - { - case RouteType.Outbound: - gateway = Global.Outbound.Gateway!.ToString(); - index = Global.Outbound.Index; - break; - case RouteType.TUNTAP: - gateway = Global.Settings.TUNTAP.Gateway; - index = Global.TUNTAP.Index; - break; - default: - throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null); - } - - string network; - ushort cidr; - try - { - var s = ipNetwork.Split('/'); - network = s[0]; - cidr = ushort.Parse(s[1]); - } - catch + var s = ipNetwork.Split('/'); + if (s.Length != 2) { Logging.Warning($"Failed to parse rule {ipNetwork}"); return false; } + IAdapter adapter; + List ipList; + + switch (routeType) + { + case RouteType.TUNTAP: + adapter = _tap; + ipList = _proxyIPs; + break; + case RouteType.Outbound: + adapter = _outbound; + ipList = _directIPs; + break; + default: + throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null); + } + + string network = s[0]; + var cidr = ushort.Parse(s[1]); + string gateway = adapter.Gateway.ToString(); + var index = adapter.Index; + bool result; switch (action) { case Action.Create: - { result = NativeMethods.CreateRoute(network, cidr, gateway, index, metric); - switch (routeType) - { - case RouteType.Outbound: - _directIPs.Add(ipNetwork); - break; - case RouteType.TUNTAP: - _proxyIPs.Add(ipNetwork); - break; - } - + ipList.Add(ipNetwork); break; - } case Action.Delete: result = NativeMethods.DeleteRoute(network, cidr, gateway, index, metric); break; diff --git a/Netch/Global.cs b/Netch/Global.cs index 68a8478c..c4cc8fa6 100644 --- a/Netch/Global.cs +++ b/Netch/Global.cs @@ -1,9 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; using System.Text.Encodings.Web; using System.Text.Json; using System.Threading; @@ -66,52 +62,6 @@ namespace Netch public static bool SupportFakeDns => LazySupportFakeDns.Value; } - /// - /// 出口适配器 - /// - public static class Outbound - { - /// - /// 索引 - /// - public static int Index = -1; - - /// - /// 网关 - /// - public static IPAddress? Gateway; - - public static NetworkInterface? Adapter; - - /// - /// 地址 - /// - public static IPAddress Address => Adapter!.GetIPProperties() - .UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork) - .Address; - } - - /// - /// TUN/TAP 适配器 - /// - public static class TUNTAP - { - /// - /// 适配器 - /// - public static NetworkInterface? Adapter; - - /// - /// 索引 - /// - public static int Index = -1; - - /// - /// 组件 ID - /// - public static string ComponentID = string.Empty; - } - /// /// 主窗体的静态实例 /// diff --git a/Netch/Models/IAdapter.cs b/Netch/Models/IAdapter.cs new file mode 100644 index 00000000..f82dae8d --- /dev/null +++ b/Netch/Models/IAdapter.cs @@ -0,0 +1,15 @@ +using System.Net; +using System.Net.NetworkInformation; + +namespace Netch.Models +{ + public interface IAdapter + { + public abstract int Index { get; } + + public abstract IPAddress Gateway { get; } + + public abstract NetworkInterface NetworkInterface { get; } + + } +} \ No newline at end of file diff --git a/Netch/Models/OutboundAdapter.cs b/Netch/Models/OutboundAdapter.cs new file mode 100644 index 00000000..55f321fc --- /dev/null +++ b/Netch/Models/OutboundAdapter.cs @@ -0,0 +1,69 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using Microsoft.Win32; +using Netch.Controllers; +using Netch.Utils; +using Vanara.PInvoke; + +namespace Netch.Models +{ + public class OutboundAdapter : IAdapter + { + public OutboundAdapter(bool logging = true) + { + // 寻找出口适配器 + if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0) + { + throw new MessageException("GetBestRoute 搜索失败"); + } + + NetworkInterface = NetworkInterface.GetAllNetworkInterfaces() + .First(ni => ni.Supports(NetworkInterfaceComponent.IPv4) && + ni.GetIPProperties().GetIPv4Properties().Index == pRoute.dwForwardIfIndex); + + Index = (int) pRoute.dwForwardIfIndex; + Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b); + _parametersRegistry = + Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{NetworkInterface.Id}", true)!; + + if (logging) + { + Logging.Info($"出口 网关 地址:{Gateway}"); + Logging.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}"); + } + } + + /// + /// 索引 + /// + public int Index { get; } + + /// + /// 网关 + /// + public IPAddress Gateway { get; } + + public NetworkInterface NetworkInterface { get; } + + + public string DNS + { + get + { + try + { + return (string) _parametersRegistry.GetValue("NameServer"); + } + catch + { + return string.Empty; + } + } + set => _parametersRegistry.SetValue("NameServer", value, RegistryValueKind.String); + } + + private readonly RegistryKey _parametersRegistry; + } +} \ No newline at end of file diff --git a/Netch/Models/TapAdapter.cs b/Netch/Models/TapAdapter.cs new file mode 100644 index 00000000..196b789f --- /dev/null +++ b/Netch/Models/TapAdapter.cs @@ -0,0 +1,30 @@ +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using Netch.Controllers; +using Netch.Utils; + +namespace Netch.Models +{ + public class TapAdapter : IAdapter + { + public TapAdapter() + { + Index = -1; + ComponentID = TUNTAP.GetComponentID() ?? throw new MessageException("TAP 适配器未安装"); + + // 根据 ComponentID 寻找 Tap适配器 + NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.Id == ComponentID); + Index = NetworkInterface.GetIPProperties().GetIPv4Properties().Index; + Logging.Info($"TAP 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}"); + } + + public string ComponentID { get; } + + public int Index { get; } + + public IPAddress Gateway => IPAddress.Parse(Global.Settings.TUNTAP.Gateway); + + public NetworkInterface NetworkInterface { get; } + } +} \ No newline at end of file diff --git a/Netch/Utils/DNS.cs b/Netch/Utils/DNS.cs index 7d5bfc17..7eb0434b 100644 --- a/Netch/Utils/DNS.cs +++ b/Netch/Utils/DNS.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net; -using Microsoft.Win32; namespace Netch.Utils { @@ -14,27 +13,6 @@ namespace Netch.Utils /// public static Hashtable Cache = new(); - /// - /// 出口网卡 DNS - /// - /// 依赖 - /// - public static string OutboundDNS - { - get - { - try - { - return (string) AdapterRegistry().GetValue("NameServer"); - } - catch - { - return string.Empty; - } - } - set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String); - } - /// /// 查询 /// @@ -64,15 +42,6 @@ namespace Netch.Utils } } - private static RegistryKey AdapterRegistry(bool write = false) - { - if (Global.Outbound.Adapter == null) - Utils.SearchOutboundAdapter(); - - return Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Global.Outbound.Adapter!.Id}", - write)!; - } - public static IEnumerable Split(string dns) { return dns.SplitRemoveEmptyEntriesAndTrimEntries(','); diff --git a/Netch/Utils/TUNTAP.cs b/Netch/Utils/TUNTAP.cs index b966c448..cce38550 100644 --- a/Netch/Utils/TUNTAP.cs +++ b/Netch/Utils/TUNTAP.cs @@ -1,7 +1,10 @@ using System; using System.Diagnostics; using System.IO; +using System.Linq; +using System.Threading; using Microsoft.Win32; +using Netch.Controllers; namespace Netch.Utils { @@ -9,35 +12,37 @@ namespace Netch.Utils { public static string TUNTAP_COMPONENT_ID_0901 = "tap0901"; public static string TUNTAP_COMPONENT_ID_0801 = "tap0801"; - public static string NETWORK_KEY = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"; - public static string ADAPTER_KEY = "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"; + public static string NETWORK_KEY = @"SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}"; + public static string ADAPTER_KEY = @"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}"; /// /// 获取 TUN/TAP 适配器 ID /// /// 适配器 ID - public static string GetComponentID() + public static string? GetComponentID() { try { - var adaptersRegistry = Registry.LocalMachine.OpenSubKey(ADAPTER_KEY); + var adaptersRegistry = Registry.LocalMachine.OpenSubKey(ADAPTER_KEY)!; - foreach (var adapterRegistryName in adaptersRegistry.GetSubKeyNames()) - if (adapterRegistryName != "Configuration" && adapterRegistryName != "Properties") - { - var adapterRegistry = adaptersRegistry.OpenSubKey(adapterRegistryName); + foreach (var keyName in adaptersRegistry.GetSubKeyNames().Where(s => s is not ("Configuration" or "Properties"))) + { + var adapterRegistry = adaptersRegistry.OpenSubKey(keyName)!; + var componentId = adapterRegistry.GetValue("ComponentId")?.ToString(); + if (componentId == null) + continue; - var adapterComponentId = adapterRegistry.GetValue("ComponentId", "").ToString(); - if (adapterComponentId == TUNTAP_COMPONENT_ID_0901 || adapterComponentId == TUNTAP_COMPONENT_ID_0801) - return adapterRegistry.GetValue("NetCfgInstanceId", "").ToString(); - } + if (componentId == TUNTAP_COMPONENT_ID_0901 || componentId == TUNTAP_COMPONENT_ID_0801) + return (string) (adapterRegistry.GetValue("NetCfgInstanceId") ?? + throw new Exception("Tap adapter have no NetCfgInstanceId key")); + } } catch (Exception e) { Logging.Warning(e.ToString()); } - return ""; + return null; } /// @@ -78,16 +83,21 @@ namespace Netch.Utils /// /// 安装tap网卡 /// - public static void addtap() + public static void AddTap() { Logging.Info("安装 TUN/TAP 适配器"); //安装Tap Driver - var installProcess = new Process - {StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "addtap.bat")}}; + using var process = Process.Start(new ProcessStartInfo + { + FileName = Path.Combine("bin/tap-driver", "addtap.bat"), + WindowStyle = ProcessWindowStyle.Hidden + })!; - installProcess.Start(); - installProcess.WaitForExit(); - installProcess.Close(); + process.WaitForExit(); + + Thread.Sleep(1000); + if (GetComponentID() == null) + throw new MessageException("TAP 驱动安装失败,找不到 ComponentID 注册表项"); } } } \ No newline at end of file diff --git a/Netch/Utils/Utils.cs b/Netch/Utils/Utils.cs index 82ae87e1..0ee22a92 100644 --- a/Netch/Utils/Utils.cs +++ b/Netch/Utils/Utils.cs @@ -13,7 +13,6 @@ using System.Threading.Tasks; using System.Windows.Forms; using MaxMind.GeoIP2; using Microsoft.Win32.TaskScheduler; -using Vanara.PInvoke; using Task = System.Threading.Tasks.Task; namespace Netch.Utils @@ -138,40 +137,6 @@ namespace Netch.Utils return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty; } - public static void SearchOutboundAdapter(bool logging = true) - { - // 寻找出口适配器 - if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0) - { - Logging.Error("GetBestRoute 搜索失败"); - throw new Exception("GetBestRoute 搜索失败"); - } - - Global.Outbound.Index = (int) pRoute.dwForwardIfIndex; - // 根据 IP Index 寻找 出口适配器 - var adapter = NetworkInterface.GetAllNetworkInterfaces() - .First(_ => - { - try - { - return _.GetIPProperties().GetIPv4Properties().Index == Global.Outbound.Index; - } - catch - { - return false; - } - }); - - Global.Outbound.Adapter = adapter; - Global.Outbound.Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b); - - if (logging) - { - Logging.Info($"出口 IPv4 地址:{Global.Outbound.Address}"); - Logging.Info($"出口 网关 地址:{Global.Outbound.Gateway}"); - Logging.Info($"出口适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.Outbound.Index}"); - } - } public static void DrawCenterComboBox(object sender, DrawItemEventArgs e) {