mirror of
https://github.com/netchx/netch.git
synced 2026-05-09 22:54:03 +08:00
Update TUNController
This commit is contained in:
@@ -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<string> _directIPs = new();
|
||||
|
||||
private readonly List<string> _proxyIPs = new();
|
||||
/// <summary>
|
||||
/// 服务器 IP 地址
|
||||
/// </summary>
|
||||
private IPAddress _serverAddresses = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 本地 DNS 服务控制器
|
||||
/// </summary>
|
||||
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<string> {"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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP停止
|
||||
/// </summary>
|
||||
@@ -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<string> ipNetworks, RouteType routeType, int metric = 0)
|
||||
private void RouteAction(Action action, in IEnumerable<string> 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<string> 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<string> 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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
/// <summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- <EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>-->
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
<AnalysisMode>Default</AnalysisMode>
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -100,9 +100,7 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Forms\Mode\Route.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\Mode\Route.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user