Update TUNController

This commit is contained in:
ChsBuffer
2021-03-27 16:24:02 +08:00
parent ad1575b3c7
commit 664b1a7e6c
8 changed files with 143 additions and 106 deletions

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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'));
}
}
}

View File

@@ -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);
}
}
}