diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index 375778a7..b5d97c1f 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; @@ -22,60 +23,54 @@ namespace Netch.Controllers private readonly List _directIPs = new(); private readonly List _proxyIPs = new(); - /// - /// 服务器 IP 地址 - /// - private IPAddress _serverAddresses = null!; - /// - /// 本地 DNS 服务控制器 - /// public readonly DNSController DNSController = new(); public string Name { get; } = "tun2socks"; private readonly OutboundAdapter _outboundAdapter = new(); private IAdapter _tunAdapter = null!; - private readonly TUNInterop _tunInterop = new(); + private IPAddress _serverAddresses = null!; public void Start(in Mode mode) { var server = MainController.Server!; _serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start - _tunInterop.Dial(NameList.TYPE_ADAPMTU, "1500"); - _tunInterop.Dial(NameList.TYPE_BYPBIND, "10.0.0.100"); - _tunInterop.Dial(NameList.TYPE_BYPLIST, "disabled"); + CheckDriver(); + Dial(NameList.TYPE_ADAPMTU, "1500"); + Dial(NameList.TYPE_BYPBIND, _outboundAdapter.Address.ToString()); + Dial(NameList.TYPE_BYPLIST, "disabled"); #region Server - _tunInterop.Dial(NameList.TYPE_TCPREST, ""); - _tunInterop.Dial(NameList.TYPE_TCPTYPE, "Socks5"); + Dial(NameList.TYPE_TCPREST, ""); + Dial(NameList.TYPE_TCPTYPE, "Socks5"); - _tunInterop.Dial(NameList.TYPE_UDPREST, ""); - _tunInterop.Dial(NameList.TYPE_UDPTYPE, "Socks5"); + Dial(NameList.TYPE_UDPREST, ""); + Dial(NameList.TYPE_UDPTYPE, "Socks5"); if (server is Socks5 socks5) { - _tunInterop.Dial(NameList.TYPE_TCPHOST, $"{server.AutoResolveHostname()}:{server.Port}"); + Dial(NameList.TYPE_TCPHOST, $"{server.AutoResolveHostname()}:{server.Port}"); - _tunInterop.Dial(NameList.TYPE_UDPHOST, $"{server.AutoResolveHostname()}:{server.Port}"); + Dial(NameList.TYPE_UDPHOST, $"{server.AutoResolveHostname()}:{server.Port}"); if (socks5.Auth()) { - _tunInterop.Dial(NameList.TYPE_TCPUSER, socks5.Username!); - _tunInterop.Dial(NameList.TYPE_TCPPASS, socks5.Password!); + Dial(NameList.TYPE_TCPUSER, socks5.Username!); + Dial(NameList.TYPE_TCPPASS, socks5.Password!); - _tunInterop.Dial(NameList.TYPE_UDPUSER, socks5.Username!); - _tunInterop.Dial(NameList.TYPE_UDPPASS, socks5.Password!); + Dial(NameList.TYPE_UDPUSER, socks5.Username!); + Dial(NameList.TYPE_UDPPASS, socks5.Password!); } } else { - _tunInterop.Dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}"); + Dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}"); - _tunInterop.Dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}"); + Dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}"); } #endregion @@ -94,19 +89,46 @@ namespace Netch.Controllers dns = new List {"127.0.0.1"}; } - _tunInterop.Dial(NameList.TYPE_DNSADDR, DnsUtils.Join(dns)); + Dial(NameList.TYPE_DNSADDR, DnsUtils.Join(dns)); #endregion - Console.WriteLine("tun2socks init"); - _tunInterop.Init(); + Logging.Debug("tun2socks init"); + Init(); _tunAdapter = new TunAdapter(); - NativeMethods.CreateUnicastIP((int) AddressFamily.InterNetwork, Global.Settings.WinTUN.Address, 24, _tunAdapter.InterfaceIndex); + NativeMethods.CreateUnicastIP((int) AddressFamily.InterNetwork, + Global.Settings.WinTUN.Address, + Utils.Utils.SubnetToCidr(Global.Settings.WinTUN.Netmask), + _tunAdapter.InterfaceIndex); + SetupRouteTable(mode); } + private readonly string BinDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll"); + private readonly string SysDriver = $@"{Environment.SystemDirectory}\wintun.dll"; + + private void CheckDriver() + { + var binHash = Utils.Utils.SHA256CheckSum(BinDriver); + var sysHash = Utils.Utils.SHA256CheckSum(SysDriver); + Logging.Info(binHash); + Logging.Info(sysHash); + if (binHash == sysHash) + return; + + try + { + File.Copy(BinDriver, SysDriver, true); + } + catch (Exception e) + { + Logging.Error(e.ToString()); + throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}"); + } + } + /// /// TUN/TAP停止 /// @@ -116,7 +138,7 @@ namespace Netch.Controllers { Task.Run(() => { - _tunInterop.Free(); + Free(); // _tunInterop.Unload(); }), Task.Run(ClearRouteTable), @@ -210,14 +232,64 @@ namespace Netch.Controllers #region Package - private void RouteAction(Action action, in IEnumerable ipNetworks, RouteType routeType, int metric = 0) + 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) + 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 = NativeMethods.CreateRoute((int) AddressFamily.InterNetwork, ip, cidr, gateway, index, metric); + ipList.Add(ipNetwork); + break; + case Action.Delete: + result = NativeMethods.DeleteRoute((int) AddressFamily.InterNetwork, ip, cidr, gateway, index, metric); + break; + default: + throw new ArgumentOutOfRangeException(nameof(action), action, null); + } + + Logging.Debug($"{action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})"); + if (!result) + Logging.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) { @@ -225,47 +297,9 @@ namespace Netch.Controllers return false; } - IAdapter adapter; - List ipList; - - switch (routeType) - { - case RouteType.TUNTAP: - adapter = _tunAdapter; - ipList = _proxyIPs; - break; - case RouteType.Outbound: - adapter = _outboundAdapter; - 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.InterfaceIndex; - - bool result; - switch (action) - { - case Action.Create: - result = NativeMethods.CreateRoute((int) AddressFamily.InterNetwork, network, cidr, gateway, index, metric); - ipList.Add(ipNetwork); - break; - case Action.Delete: - result = NativeMethods.DeleteRoute((int) AddressFamily.InterNetwork, network, cidr, gateway, index, metric); - break; - default: - throw new ArgumentOutOfRangeException(nameof(action), action, null); - } - - Logging.Debug($"{action}Route(\"{network}\", {cidr}, \"{gateway}\", {index}, {metric})"); - if (!result) - Logging.Warning($"Failed to invoke {action}Route(\"{network}\", {cidr}, \"{gateway}\", {index}, {metric})"); - - return result; + ip = s[0]; + cidr = int.Parse(s[1]); + return true; } private enum RouteType diff --git a/Netch/Controllers/TUNInterop.cs b/Netch/Controllers/TUNInterop.cs index 35e575bc..61b4da7f 100644 --- a/Netch/Controllers/TUNInterop.cs +++ b/Netch/Controllers/TUNInterop.cs @@ -35,18 +35,18 @@ namespace Netch.Controllers TYPE_UDPOBPA } - public bool Dial(NameList name, string value) + public static bool Dial(NameList name, string value) { Logging.Debug($"Dial {name} {value}"); return tun_dial(name, Encoding.UTF8.GetBytes(value)); } - public bool Init() + public static bool Init() { return tun_init(); } - public bool Free() + public static bool Free() { return tun_free(); } diff --git a/Netch/Models/OutboundAdapter.cs b/Netch/Models/OutboundAdapter.cs index aea69f97..22ea76fc 100644 --- a/Netch/Models/OutboundAdapter.cs +++ b/Netch/Models/OutboundAdapter.cs @@ -11,7 +11,7 @@ namespace Netch.Models { public class OutboundAdapter : IAdapter { - public OutboundAdapter(bool logging = true) + public OutboundAdapter() { // 寻找出口适配器 if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0) @@ -23,18 +23,16 @@ namespace Netch.Models .First(ni => ni.Supports(NetworkInterfaceComponent.IPv4) && ni.GetIPProperties().GetIPv4Properties().Index == pRoute.dwForwardIfIndex); + Address = new IPAddress(pRoute.dwForwardNextHop.S_addr); InterfaceIndex = (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: {InterfaceIndex}"); - } + Logging.Info($"出口 网关 地址:{Gateway}"); + Logging.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}"); } + public IPAddress Address { get; set; } + public string AdapterId => throw new NotImplementedException(); /// @@ -48,23 +46,5 @@ namespace Netch.Models 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/Netch.csproj b/Netch/Netch.csproj index 557c2669..391fe08a 100644 --- a/Netch/Netch.csproj +++ b/Netch/Netch.csproj @@ -14,9 +14,9 @@ latest false enable - + false + Default + true @@ -100,9 +100,7 @@ True Settings.settings - - Form - + diff --git a/Netch/Utils/PortHelper.cs b/Netch/Utils/PortHelper.cs index 27df68cc..34054f10 100644 --- a/Netch/Utils/PortHelper.cs +++ b/Netch/Utils/PortHelper.cs @@ -6,6 +6,7 @@ using System.Net.NetworkInformation; using Netch.Models; using static Vanara.PInvoke.IpHlpApi; using static Vanara.PInvoke.Ws2_32; +using Range = Netch.Models.Range; namespace Netch.Utils { diff --git a/Netch/Utils/ServerHelper.cs b/Netch/Utils/ServerHelper.cs index 6973bef9..eef6b921 100644 --- a/Netch/Utils/ServerHelper.cs +++ b/Netch/Utils/ServerHelper.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using System.Timers; using Netch.Models; +using Range = Netch.Models.Range; namespace Netch.Utils { diff --git a/Netch/Utils/Utils.cs b/Netch/Utils/Utils.cs index bd89deb0..0194b641 100644 --- a/Netch/Utils/Utils.cs +++ b/Netch/Utils/Utils.cs @@ -253,5 +253,16 @@ namespace Netch.Utils p.WaitForExit(); } + + public static int SubnetToCidr(string value) + { + var subnet = IPAddress.Parse(value); + return SubnetToCidr(subnet); + } + + public static int SubnetToCidr(IPAddress subnet) + { + return subnet.GetAddressBytes().Sum(b => Convert.ToString(b, 2).Count(c => c == '1')); + } } } \ No newline at end of file diff --git a/UnitTest/Function.cs b/UnitTest/Function.cs index 5257d497..f49f2e16 100644 --- a/UnitTest/Function.cs +++ b/UnitTest/Function.cs @@ -28,5 +28,17 @@ namespace UnitTest TestLoad(""); TestLoad("-"); } + + [TestMethod] + public void TestMaskToCidr() + { + Assert.AreEqual(Utils.SubnetToCidr("0.0.0.0"), 0); + Assert.AreEqual(Utils.SubnetToCidr("248.0.0.0"), 5); + Assert.AreEqual(Utils.SubnetToCidr("255.0.0.0"), 8); + Assert.AreEqual(Utils.SubnetToCidr("255.255.0.0"), 16); + Assert.AreEqual(Utils.SubnetToCidr("255.255.248.0"), 21); + Assert.AreEqual(Utils.SubnetToCidr("255.255.255.0"), 24); + Assert.AreEqual(Utils.SubnetToCidr("255.255.255.255"), 32); + } } } \ No newline at end of file