Refactor Get NetworkInterfaces

This commit is contained in:
ChsBuffer
2021-03-03 19:37:04 +08:00
parent f3515974f8
commit 0714a7bc12
10 changed files with 195 additions and 260 deletions

View File

@@ -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到防火墙

View File

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

View File

@@ -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
/// <summary>
/// 服务器 IP 地址
/// </summary>
private IPAddress? _serverAddresses;
private IPAddress _serverAddresses = null!;
/// <summary>
/// 本地 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<string> 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<string> {"1.1.1.1"};
}
else
{
MainController.PortCheck(53, "DNS");
DNSController.Start();
dns = "127.0.0.1";
dns = new List<string> {"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
}
}
/// <summary>
/// 搜索出口和TUNTAP适配器
/// </summary>
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<string> 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<string> 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;

View File

@@ -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;
}
/// <summary>
/// 出口适配器
/// </summary>
public static class Outbound
{
/// <summary>
/// 索引
/// </summary>
public static int Index = -1;
/// <summary>
/// 网关
/// </summary>
public static IPAddress? Gateway;
public static NetworkInterface? Adapter;
/// <summary>
/// 地址
/// </summary>
public static IPAddress Address => Adapter!.GetIPProperties()
.UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork)
.Address;
}
/// <summary>
/// TUN/TAP 适配器
/// </summary>
public static class TUNTAP
{
/// <summary>
/// 适配器
/// </summary>
public static NetworkInterface? Adapter;
/// <summary>
/// 索引
/// </summary>
public static int Index = -1;
/// <summary>
/// 组件 ID
/// </summary>
public static string ComponentID = string.Empty;
}
/// <summary>
/// 主窗体的静态实例
/// </summary>

15
Netch/Models/IAdapter.cs Normal file
View File

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

View File

@@ -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}");
}
}
/// <summary>
/// 索引
/// </summary>
public int Index { get; }
/// <summary>
/// 网关
/// </summary>
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

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

View File

@@ -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
/// </summary>
public static Hashtable Cache = new();
/// <summary>
/// 出口网卡 DNS
/// <para></para>
/// 依赖 <see cref="Global.Outbound.Adapter" />
/// </summary>
public static string OutboundDNS
{
get
{
try
{
return (string) AdapterRegistry().GetValue("NameServer");
}
catch
{
return string.Empty;
}
}
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
}
/// <summary>
/// 查询
/// </summary>
@@ -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<string> Split(string dns)
{
return dns.SplitRemoveEmptyEntriesAndTrimEntries(',');

View File

@@ -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}";
/// <summary>
/// 获取 TUN/TAP 适配器 ID
/// </summary>
/// <returns>适配器 ID</returns>
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;
}
/// <summary>
@@ -78,16 +83,21 @@ namespace Netch.Utils
/// <summary>
/// 安装tap网卡
/// </summary>
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 注册表项");
}
}
}

View File

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