From 74caeeaf427ec5db0e6f2f98404073f708b1e547 Mon Sep 17 00:00:00 2001 From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com> Date: Sun, 9 May 2021 15:31:43 +0800 Subject: [PATCH] Refactor TUNController --- Netch/Controllers/PcapController.cs | 8 +- Netch/Controllers/TUNController.cs | 329 ++++++++---------------- Netch/Interfaces/IAdapter.cs | 14 - Netch/Interops/tun2socks.cs | 1 + Netch/Models/Adapter/OutboundAdapter.cs | 44 ---- Netch/Models/Adapter/TunAdapter.cs | 28 -- Netch/Models/NetRoute.cs | 49 ++++ Netch/Utils/NetworkInterfaceUtils.cs | 58 ++++- Netch/Utils/RouteUtils.cs | 69 +++++ Netch/Utils/Utils.cs | 10 + 10 files changed, 286 insertions(+), 324 deletions(-) delete mode 100644 Netch/Interfaces/IAdapter.cs delete mode 100644 Netch/Models/Adapter/OutboundAdapter.cs delete mode 100644 Netch/Models/Adapter/TunAdapter.cs create mode 100644 Netch/Models/NetRoute.cs create mode 100644 Netch/Utils/RouteUtils.cs diff --git a/Netch/Controllers/PcapController.cs b/Netch/Controllers/PcapController.cs index 6c61bbfa..765cf3e0 100644 --- a/Netch/Controllers/PcapController.cs +++ b/Netch/Controllers/PcapController.cs @@ -8,8 +8,8 @@ using System.Threading.Tasks; using Netch.Forms; using Netch.Interfaces; using Netch.Models; -using Netch.Models.Adapter; using Netch.Servers.Socks5; +using Netch.Utils; namespace Netch.Controllers { @@ -21,8 +21,6 @@ namespace Netch.Controllers protected override IEnumerable StartedKeywords { get; set; } = new[] { "└" }; - private readonly OutboundAdapter _outbound = new(); - protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8; private LogForm? _form; @@ -34,7 +32,9 @@ namespace Netch.Controllers _form = new LogForm(Global.MainForm); _form.CreateControl(); - var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}"); + var outboundNetworkInterface = NetworkInterfaceUtils.GetBest(); + + var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.Id}"); if (server is Socks5 socks5 && !socks5.Auth()) argument.Append($" --destination {server.AutoResolveHostname()}:{server.Port}"); else diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index b404030d..f4078fad 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -1,14 +1,11 @@ using System; -using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using Netch.Enums; using Netch.Interfaces; -using Netch.Interops; using Netch.Models; -using Netch.Models.Adapter; using Netch.Servers.Socks5; using Netch.Utils; using static Netch.Interops.tun2socks; @@ -17,29 +14,32 @@ namespace Netch.Controllers { public class TUNController : IModeController { - private readonly List _directIPs = new(); - - private readonly List _proxyIPs = new(); - - public readonly DNSController DNSController = new(); - - public string Name { get; } = "tun2socks"; - - private readonly OutboundAdapter _outboundAdapter = new(); - private IAdapter _tunAdapter = null!; - private IPAddress _serverAddresses = null!; + public string Name => "tun2socks"; private const string DummyDns = "6.6.6.6"; + private readonly DNSController _aioDnsController = new(); + + private NetRoute _outbound; + + private NetRoute _tun; + + private IPAddress _serverAddresses = null!; + + private Mode _mode = null!; + public void Start(in Mode mode) { + _mode = mode; var server = MainController.Server!; _serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start + IPAddress address; + (_outbound, address) = NetRoute.GetBestRouteTemplate(); CheckDriver(); Dial(NameList.TYPE_ADAPMTU, "1500"); - Dial(NameList.TYPE_BYPBIND, _outboundAdapter.Address.ToString()); + Dial(NameList.TYPE_BYPBIND, address.ToString()); Dial(NameList.TYPE_BYPLIST, "disabled"); #region Server @@ -83,40 +83,115 @@ namespace Netch.Controllers else { MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS"); - DNSController.Start(); + _aioDnsController.Start(); Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}"); } #endregion - Global.Logger.Debug("tun2socks init"); if (!Init()) throw new MessageException("tun2socks start failed, reboot your system and start again."); - _tunAdapter = new TunAdapter(); - switch (mode.Type) - { - case ModeType.ProxyRuleIPs when Global.Settings.TUNTAP.ProxyDNS: - case ModeType.BypassRuleIPs: - _tunAdapter.NetworkInterface.SetDns(DummyDns); - break; - } + var tunIndex = (int)Interops.RouteHelper.ConvertLuidToIndex(tun_luid()); + _tun = NetRoute.TemplateBuilder(Global.Settings.TUNTAP.Gateway, tunIndex); - RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork, + Interops.RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork, Global.Settings.TUNTAP.Address, (byte)Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask), - _tunAdapter.InterfaceIndex); + (ulong)tunIndex); SetupRouteTable(mode); } - private readonly string BinDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll"); - private readonly string SysDriver = $@"{Environment.SystemDirectory}\wintun.dll"; + #region Route + + private void SetupRouteTable(Mode mode) + { + Global.MainForm.StatusText(i18N.Translate("Setup Route Table Rule")); + Global.Logger.Info("设置路由规则"); + + if (!IPAddress.IsLoopback(_serverAddresses)) + // Server Address + RouteUtils.CreateRoute(_outbound.FillTemplate(_serverAddresses.ToString(), 32)); + + // Global Bypass IPs + foreach (var ip in Global.Settings.TUNTAP.BypassIPs) + RouteUtils.CreateRouteFill(_outbound, ip); + + var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex); + switch (mode.Type) + { + case ModeType.ProxyRuleIPs: + // rules + RouteUtils.CreateRouteFill(_tun, mode.GetRules()); + + if (Global.Settings.TUNTAP.ProxyDNS) + { + tunNetworkInterface.SetDns(DummyDns); + // proxy dummy dns + RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32)); + + if (!Global.Settings.TUNTAP.UseCustomDNS) + // proxy AioDNS other dns + RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32)); + } + + break; + case ModeType.BypassRuleIPs: + RouteUtils.CreateRouteFill(_outbound, mode.GetRules()); + + tunNetworkInterface.SetDns(DummyDns); + + if (!Global.Settings.TUNTAP.UseCustomDNS) + // bypass AioDNS other dns + RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32)); + + NetworkInterfaceUtils.SetInterfaceMetric(_tun.InterfaceIndex, 0); + RouteUtils.CreateRoute(_tun.FillTemplate("0.0.0.0", 0)); + break; + } + } + + private bool ClearRouteTable() + { + if (!IPAddress.IsLoopback(_serverAddresses)) + RouteUtils.DeleteRoute(_outbound.FillTemplate(_serverAddresses.ToString(), 32)); + + foreach (var ip in Global.Settings.TUNTAP.BypassIPs) + RouteUtils.DeleteRouteFill(_outbound, ip); + + switch (_mode.Type) + { + case ModeType.BypassRuleIPs: + RouteUtils.DeleteRouteFill(_outbound, _mode.GetRules()); + NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex); + break; + } + + return true; + } + + #endregion + + public void Stop() + { + var tasks = new[] + { + Task.Run(Free), + Task.Run(ClearRouteTable), + Task.Run(_aioDnsController.Stop) + }; + + Task.WaitAll(tasks); + } private void CheckDriver() { - var binHash = Utils.Utils.SHA256CheckSum(BinDriver); - var sysHash = Utils.Utils.SHA256CheckSum(SysDriver); + string binDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll"); + string sysDriver = $@"{Environment.SystemDirectory}\wintun.dll"; + + var binHash = Utils.Utils.SHA256CheckSum(binDriver); + var sysHash = Utils.Utils.SHA256CheckSum(sysDriver); Global.Logger.Info("自带 wintun.dll Hash: " + binHash); Global.Logger.Info("系统 wintun.dll Hash: " + sysHash); if (binHash == sysHash) @@ -124,7 +199,8 @@ namespace Netch.Controllers try { - File.Copy(BinDriver, SysDriver, true); + Global.Logger.Info("Copy wintun.dll to System Directory"); + File.Copy(binDriver, sysDriver, true); } catch (Exception e) { @@ -132,194 +208,5 @@ namespace Netch.Controllers throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}"); } } - - /// - /// TUN/TAP停止 - /// - public void Stop() - { - var tasks = new[] - { - Task.Run(Free), - Task.Run(ClearRouteTable), - Task.Run(DNSController.Stop) - }; - - Task.WaitAll(tasks); - } - - /// - /// 设置绕行规则 - /// - /// 是否设置成功 - private void SetupRouteTable(Mode mode) - { - Global.MainForm.StatusText(i18N.Translate("SetupBypass")); - Global.Logger.Info("设置路由规则"); - - Global.Logger.Info("绕行 → 服务器 IP"); - if (!IPAddress.IsLoopback(_serverAddresses)) - RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound); - - Global.Logger.Info("绕行 → 全局绕过 IP"); - RouteAction(Action.Create, Global.Settings.TUNTAP.BypassIPs, RouteType.Outbound); - - #region Rule IPs - - switch (mode.Type) - { - case ModeType.ProxyRuleIPs: - // 代理规则 IP - Global.Logger.Info("代理 → 规则 IP"); - RouteAction(Action.Create, mode.GetRules(), RouteType.TUNTAP); - - if (Global.Settings.TUNTAP.ProxyDNS) - { - Global.Logger.Info("代理 → 占位 DNS"); - RouteAction(Action.Create, $"{DummyDns}/32", RouteType.TUNTAP); - - if (!Global.Settings.TUNTAP.UseCustomDNS) - { - Global.Logger.Info("代理 → AioDNS OtherDNS"); - var otherDns = Global.Settings.AioDNS.OtherDNS; - RouteAction(Action.Create, $"{otherDns[..otherDns.IndexOf(':')]}/32", RouteType.TUNTAP); - } - } - - break; - case ModeType.BypassRuleIPs: - // 绕过规则 IP - - Global.Logger.Info("绕行 → 规则 IP"); - RouteAction(Action.Create, mode.GetRules(), RouteType.Outbound); - break; - } - - #endregion - - if (mode.Type == ModeType.BypassRuleIPs) - { - Global.Logger.Info("代理 → 全局"); - SetInterface(RouteType.TUNTAP, 0); - RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP, record: false); - } - } - - private void SetInterface(RouteType routeType, int? metric = null) - { - var adapter = routeType == RouteType.Outbound ? _outboundAdapter : _tunAdapter; - - var arguments = $"interface ip set interface {adapter.InterfaceIndex} "; - if (metric != null) - arguments += $"metric={metric} "; - - Utils.Utils.ProcessRunHiddenAsync("netsh", arguments).Wait(); - } - - /// - /// 清除绕行规则 - /// - private bool ClearRouteTable() - { - var mode = MainController.Mode!; - RouteAction(Action.Delete, _directIPs, RouteType.Outbound); - RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP); - _directIPs.Clear(); - _proxyIPs.Clear(); - if (mode.Type == ModeType.BypassRuleIPs) - { - SetInterface(RouteType.Outbound); - } - - return true; - } - - #region Package - - private void RouteAction(Action action, in IEnumerable ipNetworks, RouteType routeType, int metric = 0, bool record = true) - { - foreach (var address in ipNetworks) - RouteAction(action, address, routeType, metric); - } - - private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0, bool record = true) - { - #region - - if (!TryParseIPNetwork(ipNetwork, out var ip, out var cidr)) - return false; - - IAdapter adapter = routeType switch - { - RouteType.Outbound => _outboundAdapter, - RouteType.TUNTAP => _tunAdapter, - _ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null) - }; - - List ipList = routeType switch - { - RouteType.Outbound => _directIPs, - RouteType.TUNTAP => _proxyIPs, - _ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null) - }; - - string gateway = adapter.Gateway.ToString(); - var index = adapter.InterfaceIndex; - - #endregion - - bool result; - switch (action) - { - case Action.Create: - result = RouteHelper.CreateRoute(AddressFamily.InterNetwork, ip, (byte)cidr, gateway, index, metric); - if (record) - ipList.Add(ipNetwork); - - break; - case Action.Delete: - result = RouteHelper.DeleteRoute(AddressFamily.InterNetwork, ip, (byte)cidr, gateway, index, metric); - break; - default: - throw new ArgumentOutOfRangeException(nameof(action), action, null); - } - - Global.Logger.Debug($"{action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})"); - if (!result) - Global.Logger.Warning($"Failed to invoke {action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})"); - - return result; - } - - bool TryParseIPNetwork(string ipNetwork, out string ip, out int cidr) - { - ip = null!; - cidr = 0; - - var s = ipNetwork.Split('/'); - if (s.Length != 2) - { - Global.Logger.Warning($"Failed to parse rule {ipNetwork}"); - return false; - } - - ip = s[0]; - cidr = int.Parse(s[1]); - return true; - } - - private enum RouteType - { - Outbound, - TUNTAP - } - - private enum Action - { - Create, - Delete - } - - #endregion } } \ No newline at end of file diff --git a/Netch/Interfaces/IAdapter.cs b/Netch/Interfaces/IAdapter.cs deleted file mode 100644 index 819dc023..00000000 --- a/Netch/Interfaces/IAdapter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Net; -using System.Net.NetworkInformation; - -namespace Netch.Interfaces -{ - public interface IAdapter - { - ulong InterfaceIndex { get; } - - IPAddress Gateway { get; } - - NetworkInterface NetworkInterface { get; } - } -} \ No newline at end of file diff --git a/Netch/Interops/tun2socks.cs b/Netch/Interops/tun2socks.cs index fec80bae..12cfd1e0 100644 --- a/Netch/Interops/tun2socks.cs +++ b/Netch/Interops/tun2socks.cs @@ -41,6 +41,7 @@ namespace Netch.Interops public static bool Init() { + Global.Logger.Debug("tun2socks init"); return tun_init(); } diff --git a/Netch/Models/Adapter/OutboundAdapter.cs b/Netch/Models/Adapter/OutboundAdapter.cs deleted file mode 100644 index f2467ac4..00000000 --- a/Netch/Models/Adapter/OutboundAdapter.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Net; -using System.Net.NetworkInformation; -using Netch.Interfaces; -using Netch.Utils; -using Vanara.PInvoke; - -namespace Netch.Models.Adapter -{ - public class OutboundAdapter : IAdapter - { - public OutboundAdapter() - { - // 寻找出口适配器 - if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0) - { - throw new MessageException("GetBestRoute 搜索失败"); - } - - NetworkInterface = NetworkInterfaceUtils.Get((int)pRoute.dwForwardIfIndex); - - Address = new IPAddress(pRoute.dwForwardNextHop.S_addr); - InterfaceIndex = (ulong)pRoute.dwForwardIfIndex; - Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b); - - Global.Logger.Info($"出口 网关 地址:{Gateway}"); - Global.Logger.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}"); - } - - public IPAddress Address { get; } - - /// - /// 索引 - /// - public ulong InterfaceIndex { get; } - - /// - /// 网关 - /// - public IPAddress Gateway { get; } - - public NetworkInterface NetworkInterface { get; } - } -} \ No newline at end of file diff --git a/Netch/Models/Adapter/TunAdapter.cs b/Netch/Models/Adapter/TunAdapter.cs deleted file mode 100644 index dd1f73c4..00000000 --- a/Netch/Models/Adapter/TunAdapter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Net; -using System.Net.NetworkInformation; -using Netch.Interfaces; -using Netch.Interops; -using Netch.Utils; - -namespace Netch.Models.Adapter -{ - public class TunAdapter : IAdapter - { - public TunAdapter() - { - - InterfaceIndex = RouteHelper.ConvertLuidToIndex(tun2socks.tun_luid()); - NetworkInterface = NetworkInterfaceUtils.Get((int)InterfaceIndex); - Gateway = IPAddress.Parse(Global.Settings.TUNTAP.Gateway); - - Global.Logger.Info($"WinTUN 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}"); - } - - - public ulong InterfaceIndex { get; } - - public IPAddress Gateway { get; } - - public NetworkInterface NetworkInterface { get; } - } -} diff --git a/Netch/Models/NetRoute.cs b/Netch/Models/NetRoute.cs new file mode 100644 index 00000000..74e5bad1 --- /dev/null +++ b/Netch/Models/NetRoute.cs @@ -0,0 +1,49 @@ +using System; +using System.Net; +using Vanara.PInvoke; + +namespace Netch.Models +{ + public struct NetRoute + { + public static NetRoute TemplateBuilder(string gateway, int interfaceIndex, int metric = 0) + { + return new() + { + Gateway = gateway, + InterfaceIndex = interfaceIndex, + Metric = metric + }; + } + + public static (NetRoute, IPAddress address) GetBestRouteTemplate() + { + if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var route) != 0) + throw new MessageException("GetBestRoute 搜索失败"); + + var address = new IPAddress(route.dwForwardNextHop.S_addr); + var gateway = new IPAddress(route.dwForwardNextHop.S_un_b); + return (TemplateBuilder(gateway.ToString(), (int)route.dwForwardIfIndex), address); + } + + public int InterfaceIndex; + + public string Gateway; + + public string Network; + + public byte Cidr; + + public int Metric; + + public NetRoute FillTemplate(string network, byte cidr, int? metric = null) + { + Network = network; + Cidr = cidr; + if (metric != null) + Metric = (int)metric; + + return this; + } + } +} \ No newline at end of file diff --git a/Netch/Utils/NetworkInterfaceUtils.cs b/Netch/Utils/NetworkInterfaceUtils.cs index fc36404d..b018e31e 100644 --- a/Netch/Utils/NetworkInterfaceUtils.cs +++ b/Netch/Utils/NetworkInterfaceUtils.cs @@ -1,12 +1,31 @@ using System; using System.Linq; using System.Management; +using System.Net; using System.Net.NetworkInformation; +using System.Net.Sockets; +using Netch.Models; +using Vanara.PInvoke; namespace Netch.Utils { public static class NetworkInterfaceUtils { + public static NetworkInterface GetBest(AddressFamily addressFamily = AddressFamily.InterNetwork) + { + var ipAddress = addressFamily switch + { + AddressFamily.InterNetwork => "114.114.114.114", + AddressFamily.InterNetworkV6 => throw new NotImplementedException(), + _ => throw new ArgumentOutOfRangeException(nameof(addressFamily), addressFamily, null) + }; + + if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0), 0, out var route) != 0) + throw new MessageException("GetBestRoute 搜索失败"); + + return Get((int)route.dwForwardIfIndex); + } + /// /// /// @@ -14,25 +33,38 @@ namespace Netch.Utils /// public static NetworkInterface Get(int interfaceIndex) { - return NetworkInterface.GetAllNetworkInterfaces() - .First(n => - { - var ipProperties = n.GetIPProperties(); - int index; - if (n.Supports(NetworkInterfaceComponent.IPv4)) - index = ipProperties.GetIPv4Properties().Index; - else if (n.Supports(NetworkInterfaceComponent.IPv6)) - index = ipProperties.GetIPv6Properties().Index; - else - return false; + return NetworkInterface.GetAllNetworkInterfaces().First(n => n.GetIndex() == interfaceIndex); + } - return index == interfaceIndex; - }); + public static NetworkInterface Get(string description) + { + return NetworkInterface.GetAllNetworkInterfaces().First(n => n.Description == description); + } + + public static void SetInterfaceMetric(int interfaceIndex, int? metric = null) + { + var arguments = $"interface ip set interface {interfaceIndex} "; + if (metric != null) + arguments += $"metric={metric} "; + + Utils.ProcessRunHiddenAsync("netsh", arguments).Wait(); } } public static class NetworkInterfaceExtension { + public static int GetIndex(this NetworkInterface ni) + { + var ipProperties = ni.GetIPProperties(); + if (ni.Supports(NetworkInterfaceComponent.IPv4)) + return ipProperties.GetIPv4Properties().Index; + + if (ni.Supports(NetworkInterfaceComponent.IPv6)) + return ipProperties.GetIPv6Properties().Index; + + throw new Exception(); + } + public static void SetDns(this NetworkInterface ni, string primaryDns, string? secondDns = null) { void VerifyDns(ref string s) diff --git a/Netch/Utils/RouteUtils.cs b/Netch/Utils/RouteUtils.cs new file mode 100644 index 00000000..8917abbb --- /dev/null +++ b/Netch/Utils/RouteUtils.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Sockets; +using Netch.Interops; +using Netch.Models; + +namespace Netch.Utils +{ + public static class RouteUtils + { + public static void CreateRouteFill(NetRoute template, IEnumerable rules, int? metric = null) + { + foreach (var rule in rules) + CreateRouteFill(template, rule, metric); + } + + public static bool CreateRouteFill(NetRoute template, string rule, int? metric = null) + { + if (!TryParseIPNetwork(rule, out var network, out var cidr)) + { + Global.Logger.Warning($"invalid rule {rule}"); + return false; + } + + return CreateRoute(template.FillTemplate(network, (byte)cidr, metric)); + } + + public static bool CreateRoute(NetRoute o) + { + return RouteHelper.CreateRoute(AddressFamily.InterNetwork, o.Network, o.Cidr, o.Gateway, (ulong)o.InterfaceIndex, o.Metric); + } + + public static void DeleteRouteFill(NetRoute template, IEnumerable rules, int? metric = null) + { + foreach (var rule in rules) + DeleteRouteFill(template, rule, metric); + } + + public static bool DeleteRouteFill(NetRoute template, string rule, int? metric = null) + { + if (!TryParseIPNetwork(rule, out var network, out var cidr)) + { + Global.Logger.Warning($"invalid rule {rule}"); + return false; + } + + return DeleteRoute(template.FillTemplate(network, (byte)cidr, metric)); + } + + public static bool DeleteRoute(NetRoute o) + { + return RouteHelper.DeleteRoute(AddressFamily.InterNetwork, o.Network, o.Cidr, o.Gateway, (ulong)o.InterfaceIndex, o.Metric); + } + + public static bool TryParseIPNetwork(string ipNetwork, [NotNullWhen(true)] out string? ip, out int cidr) + { + ip = null; + cidr = 0; + + var s = ipNetwork.Split('/'); + if (s.Length != 2) + return false; + + ip = s[0]; + cidr = int.Parse(s[1]); + return true; + } + } +} \ No newline at end of file diff --git a/Netch/Utils/Utils.cs b/Netch/Utils/Utils.cs index f9ae9adf..3ad8bf8f 100644 --- a/Netch/Utils/Utils.cs +++ b/Netch/Utils/Utils.cs @@ -275,5 +275,15 @@ namespace Netch.Utils return host; } + + public static string GetHostFromUri(string str) + { + var startIndex = str.LastIndexOf('/'); + if (startIndex != -1) + str = str[(startIndex + 1)..]; + + var endIndex = str.IndexOf(':'); + return endIndex == -1 ? str : str[..endIndex]; + } } } \ No newline at end of file