mirror of
https://github.com/netchx/netch.git
synced 2026-03-18 18:13:21 +08:00
- Migrate to xjasonlyu/tun2socks
- Fix Starting Controller misc UI block - Fix didn't stop Controller when starting Controller
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using static Netch.Interops.AioDNS;
|
||||
|
||||
namespace Netch.Controllers
|
||||
@@ -10,26 +10,24 @@ namespace Netch.Controllers
|
||||
{
|
||||
public string Name => "DNS Service";
|
||||
|
||||
public async Task StopAsync()
|
||||
public async Task StartAsync(string listenAddress)
|
||||
{
|
||||
await FreeAsync();
|
||||
}
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
|
||||
|
||||
var aioDnsConfig = Global.Settings.AioDNS;
|
||||
var listenAddress = Global.Settings.LocalAddress;
|
||||
|
||||
Dial(NameList.TYPE_REST, "");
|
||||
Dial(NameList.TYPE_LIST, Path.GetFullPath(Constants.AioDnsRuleFile));
|
||||
// TODO remove ListenPort setting
|
||||
Dial(NameList.TYPE_LISN, $"{listenAddress}:{aioDnsConfig.ListenPort}");
|
||||
Dial(NameList.TYPE_CDNS, $"{aioDnsConfig.ChinaDNS}");
|
||||
Dial(NameList.TYPE_ODNS, $"{aioDnsConfig.OtherDNS}");
|
||||
|
||||
if (!await InitAsync())
|
||||
throw new Exception("AioDNS start failed.");
|
||||
throw new MessageException("AioDNS start failed.");
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
await FreeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,11 @@ namespace Netch.Controllers
|
||||
if (Lock.CurrentCount == 0)
|
||||
{
|
||||
(await Lock.EnterAsync()).Dispose();
|
||||
return;
|
||||
if (ServerController == null && ModeController == null)
|
||||
// stopped
|
||||
return;
|
||||
|
||||
// else begin stop
|
||||
}
|
||||
|
||||
using var _ = await Lock.EnterAsync();
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
var dnsStr = _mode.FilterDNS != null ? _mode.DNSHost : _rdrConfig.DNSHost;
|
||||
|
||||
dnsStr = dnsStr.ValueOrDefault() ?? Constants.DefaultPrimaryDNS;
|
||||
dnsStr = dnsStr.ValueOrDefault() ?? $"{Constants.DefaultPrimaryDNS}:53";
|
||||
|
||||
var dns = IPEndPoint.Parse(dnsStr);
|
||||
if (dns.Port == 0)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
@@ -11,27 +13,34 @@ using Netch.Models.Modes.TunMode;
|
||||
using Netch.Servers;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
using static Netch.Interops.tun2socks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNController : IModeController
|
||||
public class TUNController : Guard, IModeController
|
||||
{
|
||||
private const string DummyDns = "6.6.6.6";
|
||||
|
||||
private readonly DNSController _aioDnsController = new();
|
||||
|
||||
private TunMode _mode = null!;
|
||||
private IPAddress? _serverRemoteAddress;
|
||||
private TUNConfig _tunConfig = null!;
|
||||
private bool _routeSetuped = false;
|
||||
|
||||
private NetRoute _tun;
|
||||
private NetworkInterface _tunNetworkInterface = null!;
|
||||
private NetRoute _outbound;
|
||||
|
||||
public string Name => "tun2socks";
|
||||
public override string Name => "tun2socks";
|
||||
|
||||
public ModeFeature Features => ModeFeature.SupportSocks5Auth;
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; } = new[] { "Creating adapter" };
|
||||
|
||||
protected override IEnumerable<string> FailedKeywords { get; } = new[] { "panic" };
|
||||
|
||||
public TUNController() : base("tun2socks.exe")
|
||||
{
|
||||
}
|
||||
|
||||
public async Task StartAsync(Socks5Server server, Mode mode)
|
||||
{
|
||||
if (mode is not TunMode tunMode)
|
||||
@@ -51,51 +60,40 @@ namespace Netch.Controllers
|
||||
_outbound = NetRoute.GetBestRouteTemplate();
|
||||
CheckDriver();
|
||||
|
||||
Dial(NameList.TYPE_ADAPMTU, "1500");
|
||||
Dial(NameList.TYPE_BYPBIND, _outbound.Gateway);
|
||||
Dial(NameList.TYPE_BYPLIST, "disabled");
|
||||
var proxy = server.Auth()
|
||||
? $"socks5://{server.Username}:{server.Password}@{await server.AutoResolveHostnameAsync()}:{server.Port}"
|
||||
: $"socks5://{await server.AutoResolveHostnameAsync()}:{server.Port}";
|
||||
|
||||
#region Server
|
||||
|
||||
Dial(NameList.TYPE_TCPREST, "");
|
||||
Dial(NameList.TYPE_TCPTYPE, "Socks5");
|
||||
|
||||
Dial(NameList.TYPE_UDPREST, "");
|
||||
Dial(NameList.TYPE_UDPTYPE, "Socks5");
|
||||
|
||||
Dial(NameList.TYPE_TCPHOST, $"{await server.AutoResolveHostnameAsync()}:{server.Port}");
|
||||
|
||||
Dial(NameList.TYPE_UDPHOST, $"{await server.AutoResolveHostnameAsync()}:{server.Port}");
|
||||
|
||||
if (server.Auth())
|
||||
const string interfaceName = "netch";
|
||||
var arguments = new object?[]
|
||||
{
|
||||
Dial(NameList.TYPE_TCPUSER, server.Username!);
|
||||
Dial(NameList.TYPE_TCPPASS, server.Password!);
|
||||
// -device tun://aioCloud -proxy socks5://127.0.0.1:7890
|
||||
"-device", $"tun://{interfaceName}",
|
||||
"-proxy", proxy,
|
||||
"-mtu", "1500"
|
||||
};
|
||||
|
||||
Dial(NameList.TYPE_UDPUSER, server.Username!);
|
||||
Dial(NameList.TYPE_UDPPASS, server.Password!);
|
||||
await StartGuardAsync(Arguments.Format(arguments));
|
||||
|
||||
// Wait for adapter to be created
|
||||
for (var i = 0; i < 20; i++)
|
||||
{
|
||||
await Task.Delay(300);
|
||||
try
|
||||
{
|
||||
_tunNetworkInterface = NetworkInterfaceUtils.Get(ni => ni.Name.StartsWith(interfaceName));
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
if (_tunNetworkInterface == null)
|
||||
throw new MessageException("Create wintun adapter failed");
|
||||
|
||||
#region DNS
|
||||
|
||||
if (_tunConfig.UseCustomDNS)
|
||||
{
|
||||
Dial(NameList.TYPE_DNSADDR, _tunConfig.HijackDNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _aioDnsController.StartAsync();
|
||||
Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (!Init())
|
||||
throw new MessageException("tun2socks start failed.");
|
||||
|
||||
var tunIndex = (int)RouteHelper.ConvertLuidToIndex(tun_luid());
|
||||
var tunIndex = _tunNetworkInterface.GetIndex();
|
||||
_tun = NetRoute.TemplateBuilder(_tunConfig.Gateway, tunIndex);
|
||||
|
||||
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
@@ -103,14 +101,14 @@ namespace Netch.Controllers
|
||||
(byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask),
|
||||
(ulong)tunIndex);
|
||||
|
||||
SetupRouteTable();
|
||||
await SetupRouteTableAsync();
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
public override async Task StopAsync()
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
FreeAsync(),
|
||||
StopGuardAsync(),
|
||||
Task.Run(ClearRouteTable),
|
||||
_aioDnsController.StopAsync()
|
||||
};
|
||||
@@ -120,35 +118,33 @@ namespace Netch.Controllers
|
||||
|
||||
private void CheckDriver()
|
||||
{
|
||||
string binDriver = Path.Combine(Global.NetchDir, Constants.WintunDllFile);
|
||||
string sysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
|
||||
|
||||
var binHash = Utils.Utils.SHA256CheckSum(binDriver);
|
||||
var sysHash = Utils.Utils.SHA256CheckSum(sysDriver);
|
||||
Log.Information("Built-in wintun.dll Hash: {Hash}", binHash);
|
||||
Log.Information("Installed wintun.dll Hash: {Hash}", sysHash);
|
||||
if (binHash == sysHash)
|
||||
return;
|
||||
|
||||
var f = $@"{Environment.SystemDirectory}\wintun.dll";
|
||||
try
|
||||
{
|
||||
Log.Information("Copy wintun.dll to System Directory");
|
||||
File.Copy(binDriver, sysDriver, true);
|
||||
if (File.Exists(f))
|
||||
{
|
||||
Log.Information($"Remove unused \"{f}\"");
|
||||
File.Delete(f);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
catch
|
||||
{
|
||||
Log.Error(e, "Copy wintun.dll failed");
|
||||
throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}");
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
#region Route
|
||||
|
||||
private void SetupRouteTable()
|
||||
private async Task SetupRouteTableAsync()
|
||||
{
|
||||
// _outbound: not go through proxy
|
||||
// _tun: tun -> socks5
|
||||
// aiodns: a simple dns server with dns routing
|
||||
|
||||
|
||||
_routeSetuped = true;
|
||||
Global.MainForm.StatusText(i18N.Translate("Setup Route Table Rule"));
|
||||
|
||||
var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex);
|
||||
// Server Address
|
||||
if (_serverRemoteAddress != null)
|
||||
RouteUtils.CreateRoute(_outbound.FillTemplate(_serverRemoteAddress.ToString(), 32));
|
||||
@@ -161,21 +157,33 @@ namespace Netch.Controllers
|
||||
RouteUtils.CreateRouteFill(_outbound, _mode.Bypass);
|
||||
|
||||
// dns
|
||||
// NOTICE: DNS metric is network interface metric
|
||||
tunNetworkInterface.SetDns(DummyDns);
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32));
|
||||
|
||||
if (!_tunConfig.UseCustomDNS)
|
||||
if (_tunConfig.UseCustomDNS)
|
||||
{
|
||||
if (_tunConfig.ProxyDNS)
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(_tunConfig.DNS, 32));
|
||||
|
||||
_tunNetworkInterface.SetDns(_tunConfig.DNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// aiodns
|
||||
RouteUtils.CreateRoute(_outbound.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32));
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32));
|
||||
// aiodns listen on tun interface
|
||||
await _aioDnsController.StartAsync(Global.Settings.TUNTAP.Address);
|
||||
|
||||
_tunNetworkInterface.SetDns(_tunConfig.Address);
|
||||
}
|
||||
|
||||
// set tun interface's metric to the highest to let Windows use the interface's DNS
|
||||
NetworkInterfaceUtils.SetInterfaceMetric(_tun.InterfaceIndex, 0);
|
||||
}
|
||||
|
||||
private void ClearRouteTable()
|
||||
{
|
||||
if (!_routeSetuped)
|
||||
return;
|
||||
|
||||
if (_serverRemoteAddress != null)
|
||||
RouteUtils.DeleteRoute(_outbound.FillTemplate(_serverRemoteAddress.ToString(), 32));
|
||||
|
||||
|
||||
@@ -548,7 +548,11 @@ namespace Netch.Forms
|
||||
|
||||
try
|
||||
{
|
||||
await MainController.StartAsync(server, mode);
|
||||
// "async all the way"
|
||||
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#async-all-the-way
|
||||
|
||||
// here is a dirty hack because the MainController don't need to switch back to UI thread, let it run in threadpool
|
||||
await Task.Run(async () => await MainController.StartAsync(server, mode));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Netch.Forms.ModeForms
|
||||
BindSyncGlobalCheckBox(HandleTCPCheckBox, b => _mode.FilterTCP = b, _mode.FilterTCP, g.FilterTCP);
|
||||
BindSyncGlobalCheckBox(HandleUDPCheckBox, b => _mode.FilterUDP = b, _mode.FilterUDP, g.FilterUDP);
|
||||
BindSyncGlobalCheckBox(HandleDNSCheckBox, b => _mode.FilterDNS = b, _mode.FilterDNS, g.FilterDNS);
|
||||
BindTextBox(DNSTextBox, s => IPEndPoint.TryParse(s, out _), s => _mode.DNSHost = s, _mode.DNSHost ?? Constants.DefaultPrimaryDNS);
|
||||
BindTextBox(DNSTextBox, s => IPEndPoint.TryParse(s, out _), s => _mode.DNSHost = s, _mode.DNSHost ?? $"{Constants.DefaultPrimaryDNS}:53");
|
||||
|
||||
BindSyncGlobalCheckBox(HandleProcDNSCheckBox, b => _mode.HandleOnlyDNS = b, _mode.HandleOnlyDNS, g.HandleOnlyDNS);
|
||||
BindSyncGlobalCheckBox(ProxyDNSCheckBox, b => _mode.DNSProxy = b, _mode.DNSProxy, g.DNSProxy);
|
||||
|
||||
@@ -67,6 +67,8 @@ namespace Netch.Forms.ModeForms
|
||||
return;
|
||||
}
|
||||
|
||||
SaveBinds();
|
||||
|
||||
if (IsCreateMode)
|
||||
{
|
||||
var relativePath = FilenameTextBox.Text;
|
||||
@@ -86,8 +88,10 @@ namespace Netch.Forms.ModeForms
|
||||
{
|
||||
_mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
ModeService.Instance.Sort();
|
||||
}
|
||||
|
||||
Global.MainForm.ModeComboBox.SelectedItem = _mode;
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
53
Netch/Forms/SettingForm.Designer.cs
generated
53
Netch/Forms/SettingForm.Designer.cs
generated
@@ -59,8 +59,8 @@ namespace Netch.Forms
|
||||
this.ICMPDelayTextBox = new System.Windows.Forms.TextBox();
|
||||
this.FilterDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.DNSHijackHostTextBox = new System.Windows.Forms.TextBox();
|
||||
this.DNSProxyCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.HandleProcDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.DNSProxyCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ChildProcessHandleCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.WinTUNTabPage = new System.Windows.Forms.TabPage();
|
||||
this.WinTUNGroupBox = new System.Windows.Forms.GroupBox();
|
||||
@@ -347,7 +347,7 @@ namespace Netch.Forms
|
||||
this.FilterTCPCheckBox.AutoSize = true;
|
||||
this.FilterTCPCheckBox.Location = new System.Drawing.Point(16, 16);
|
||||
this.FilterTCPCheckBox.Name = "FilterTCPCheckBox";
|
||||
this.FilterTCPCheckBox.Size = new System.Drawing.Size(81, 21);
|
||||
this.FilterTCPCheckBox.Size = new System.Drawing.Size(94, 21);
|
||||
this.FilterTCPCheckBox.TabIndex = 1;
|
||||
this.FilterTCPCheckBox.Text = "Handle TCP";
|
||||
this.FilterTCPCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -357,7 +357,7 @@ namespace Netch.Forms
|
||||
this.FilterUDPCheckBox.AutoSize = true;
|
||||
this.FilterUDPCheckBox.Location = new System.Drawing.Point(216, 16);
|
||||
this.FilterUDPCheckBox.Name = "FilterUDPCheckBox";
|
||||
this.FilterUDPCheckBox.Size = new System.Drawing.Size(84, 21);
|
||||
this.FilterUDPCheckBox.Size = new System.Drawing.Size(97, 21);
|
||||
this.FilterUDPCheckBox.TabIndex = 2;
|
||||
this.FilterUDPCheckBox.Text = "Handle UDP";
|
||||
this.FilterUDPCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -367,7 +367,7 @@ namespace Netch.Forms
|
||||
this.FilterICMPCheckBox.AutoSize = true;
|
||||
this.FilterICMPCheckBox.Location = new System.Drawing.Point(16, 48);
|
||||
this.FilterICMPCheckBox.Name = "FilterICMPCheckBox";
|
||||
this.FilterICMPCheckBox.Size = new System.Drawing.Size(90, 21);
|
||||
this.FilterICMPCheckBox.Size = new System.Drawing.Size(103, 21);
|
||||
this.FilterICMPCheckBox.TabIndex = 3;
|
||||
this.FilterICMPCheckBox.Text = "Handle ICMP";
|
||||
this.FilterICMPCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -386,7 +386,7 @@ namespace Netch.Forms
|
||||
this.ICMPDelayLabel.AutoSize = true;
|
||||
this.ICMPDelayLabel.Location = new System.Drawing.Point(48, 80);
|
||||
this.ICMPDelayLabel.Name = "ICMPDelayLabel";
|
||||
this.ICMPDelayLabel.Size = new System.Drawing.Size(100, 17);
|
||||
this.ICMPDelayLabel.Size = new System.Drawing.Size(99, 17);
|
||||
this.ICMPDelayLabel.TabIndex = 3;
|
||||
this.ICMPDelayLabel.Text = "ICMP delay(ms)";
|
||||
//
|
||||
@@ -404,7 +404,7 @@ namespace Netch.Forms
|
||||
this.FilterDNSCheckBox.AutoSize = true;
|
||||
this.FilterDNSCheckBox.Location = new System.Drawing.Point(16, 112);
|
||||
this.FilterDNSCheckBox.Name = "FilterDNSCheckBox";
|
||||
this.FilterDNSCheckBox.Size = new System.Drawing.Size(85, 21);
|
||||
this.FilterDNSCheckBox.Size = new System.Drawing.Size(191, 21);
|
||||
this.FilterDNSCheckBox.TabIndex = 5;
|
||||
this.FilterDNSCheckBox.Text = "Handle DNS (DNS hijacking)";
|
||||
this.FilterDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -418,34 +418,34 @@ namespace Netch.Forms
|
||||
this.DNSHijackHostTextBox.TabIndex = 6;
|
||||
this.DNSHijackHostTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// DNSProxyCheckBox
|
||||
//
|
||||
this.DNSProxyCheckBox.AutoSize = true;
|
||||
this.DNSProxyCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterDNSCheckBox, "Checked", true));
|
||||
this.DNSProxyCheckBox.Location = new System.Drawing.Point(16, 208);
|
||||
this.DNSProxyCheckBox.Name = "DNSProxyCheckBox";
|
||||
this.DNSProxyCheckBox.Size = new System.Drawing.Size(184, 21);
|
||||
this.DNSProxyCheckBox.TabIndex = 8;
|
||||
this.DNSProxyCheckBox.Text = "Handle DNS through proxy";
|
||||
this.DNSProxyCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// HandleProcDNSCheckBox
|
||||
//
|
||||
this.HandleProcDNSCheckBox.AutoSize = true;
|
||||
this.HandleProcDNSCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterDNSCheckBox, "Checked", true));
|
||||
this.HandleProcDNSCheckBox.Location = new System.Drawing.Point(16, 176);
|
||||
this.HandleProcDNSCheckBox.Name = "HandleProcDNSCheckBox";
|
||||
this.HandleProcDNSCheckBox.Size = new System.Drawing.Size(203, 21);
|
||||
this.HandleProcDNSCheckBox.Size = new System.Drawing.Size(208, 21);
|
||||
this.HandleProcDNSCheckBox.TabIndex = 7;
|
||||
this.HandleProcDNSCheckBox.Text = "Handle handled process's DNS";
|
||||
this.HandleProcDNSCheckBox.Text = "Handle handled process\'s DNS";
|
||||
this.HandleProcDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// DNSProxyCheckBox
|
||||
//
|
||||
this.DNSProxyCheckBox.AutoSize = true;
|
||||
this.DNSProxyCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterDNSCheckBox, "Checked", true));
|
||||
this.DNSProxyCheckBox.Location = new System.Drawing.Point(16, 208);
|
||||
this.DNSProxyCheckBox.Name = "DNSProxyCheckBox";
|
||||
this.DNSProxyCheckBox.Size = new System.Drawing.Size(185, 21);
|
||||
this.DNSProxyCheckBox.TabIndex = 8;
|
||||
this.DNSProxyCheckBox.Text = "Handle DNS through proxy";
|
||||
this.DNSProxyCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ChildProcessHandleCheckBox
|
||||
//
|
||||
this.ChildProcessHandleCheckBox.AutoSize = true;
|
||||
this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(16, 240);
|
||||
this.ChildProcessHandleCheckBox.Name = "ChildProcessHandleCheckBox";
|
||||
this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(150, 21);
|
||||
this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(149, 21);
|
||||
this.ChildProcessHandleCheckBox.TabIndex = 9;
|
||||
this.ChildProcessHandleCheckBox.Text = "Handle child process";
|
||||
this.ChildProcessHandleCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -536,9 +536,9 @@ namespace Netch.Forms
|
||||
this.TUNTAPDNSLabel.AutoSize = true;
|
||||
this.TUNTAPDNSLabel.Location = new System.Drawing.Point(9, 112);
|
||||
this.TUNTAPDNSLabel.Name = "TUNTAPDNSLabel";
|
||||
this.TUNTAPDNSLabel.Size = new System.Drawing.Size(73, 17);
|
||||
this.TUNTAPDNSLabel.Size = new System.Drawing.Size(34, 17);
|
||||
this.TUNTAPDNSLabel.TabIndex = 6;
|
||||
this.TUNTAPDNSLabel.Text = "DNS Hijack";
|
||||
this.TUNTAPDNSLabel.Text = "DNS";
|
||||
//
|
||||
// TUNTAPDNSTextBox
|
||||
//
|
||||
@@ -554,7 +554,7 @@ namespace Netch.Forms
|
||||
this.UseCustomDNSCheckBox.AutoSize = true;
|
||||
this.UseCustomDNSCheckBox.Location = new System.Drawing.Point(10, 139);
|
||||
this.UseCustomDNSCheckBox.Name = "UseCustomDNSCheckBox";
|
||||
this.UseCustomDNSCheckBox.Size = new System.Drawing.Size(127, 21);
|
||||
this.UseCustomDNSCheckBox.Size = new System.Drawing.Size(125, 21);
|
||||
this.UseCustomDNSCheckBox.TabIndex = 8;
|
||||
this.UseCustomDNSCheckBox.Text = "Use custom DNS";
|
||||
this.UseCustomDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -562,12 +562,13 @@ namespace Netch.Forms
|
||||
//
|
||||
// ProxyDNSCheckBox
|
||||
//
|
||||
this.ProxyDNSCheckBox.DataBindings.Add((new System.Windows.Forms.Binding("Visible", UseCustomDNSCheckBox, "Checked", true)));
|
||||
this.ProxyDNSCheckBox.AutoSize = true;
|
||||
this.ProxyDNSCheckBox.Location = new System.Drawing.Point(175, 139);
|
||||
this.ProxyDNSCheckBox.Name = "ProxyDNSCheckBox";
|
||||
this.ProxyDNSCheckBox.Size = new System.Drawing.Size(228, 21);
|
||||
this.ProxyDNSCheckBox.Size = new System.Drawing.Size(89, 21);
|
||||
this.ProxyDNSCheckBox.TabIndex = 9;
|
||||
this.ProxyDNSCheckBox.Text = "Proxy DNS in Proxy Rule IPs Mode";
|
||||
this.ProxyDNSCheckBox.Text = "Proxy DNS";
|
||||
this.ProxyDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// GlobalBypassIPsButton
|
||||
@@ -931,6 +932,7 @@ namespace Netch.Forms
|
||||
this.AioDNSListenPortLabel.Size = new System.Drawing.Size(69, 17);
|
||||
this.AioDNSListenPortLabel.TabIndex = 4;
|
||||
this.AioDNSListenPortLabel.Text = "Listen Port";
|
||||
this.AioDNSListenPortLabel.Visible = false;
|
||||
//
|
||||
// AioDNSListenPortTextBox
|
||||
//
|
||||
@@ -939,6 +941,7 @@ namespace Netch.Forms
|
||||
this.AioDNSListenPortTextBox.Size = new System.Drawing.Size(80, 23);
|
||||
this.AioDNSListenPortTextBox.TabIndex = 5;
|
||||
this.AioDNSListenPortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.AioDNSListenPortTextBox.Visible = false;
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
|
||||
@@ -129,9 +129,9 @@ namespace Netch.Forms
|
||||
s =>
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
Global.Settings.TUNTAP.HijackDNS = s;
|
||||
Global.Settings.TUNTAP.DNS = s;
|
||||
},
|
||||
Global.Settings.TUNTAP.HijackDNS);
|
||||
Global.Settings.TUNTAP.DNS);
|
||||
|
||||
BindCheckBox(ProxyDNSCheckBox, b => Global.Settings.TUNTAP.ProxyDNS = b, Global.Settings.TUNTAP.ProxyDNS);
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Netch.Forms
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object? sender, EventArgs? e)
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.HijackDNS;
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS;
|
||||
else
|
||||
TUNTAPDNSTextBox.Text = "AioDNS";
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Netch.Interops
|
||||
{
|
||||
return await Task.Run(Init).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
public static async Task FreeAsync()
|
||||
{
|
||||
await Task.Run(Free).ConfigureAwait(false);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.NetworkManagement.IpHelper;
|
||||
using static Windows.Win32.PInvoke;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class RouteHelper
|
||||
public static unsafe class RouteHelper
|
||||
{
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong ConvertLuidToIndex(ulong id);
|
||||
@@ -11,8 +15,51 @@ namespace Netch.Interops
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateIPv4(string address, string netmask, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
|
||||
public static bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index)
|
||||
{
|
||||
MIB_UNICASTIPADDRESS_ROW addr;
|
||||
InitializeUnicastIpAddressEntry(&addr);
|
||||
|
||||
addr.InterfaceIndex = (uint)index;
|
||||
addr.OnLinkPrefixLength = cidr;
|
||||
|
||||
if (inet == AddressFamily.InterNetwork)
|
||||
{
|
||||
addr.Address.Ipv4.sin_family = (ushort)ADDRESS_FAMILY.AF_INET;
|
||||
if (inet_pton((int)inet, address, &addr.Address.Ipv4.sin_addr) == 0)
|
||||
return false;
|
||||
}
|
||||
else if (inet == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
addr.Address.Ipv6.sin6_family = (ushort)ADDRESS_FAMILY.AF_INET6;
|
||||
if (inet_pton((int)inet, address, &addr.Address.Ipv6.sin6_addr) == 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a Handle to be notified of IP address changes
|
||||
HANDLE handle = default;
|
||||
using var obj = new Semaphore(1, 1);
|
||||
void Callback(void* context, MIB_UNICASTIPADDRESS_ROW* row, MIB_NOTIFICATION_TYPE type) => obj.Release(1);
|
||||
|
||||
// Use NotifyUnicastIpAddressChange to determine when the address is ready
|
||||
obj.WaitOne();
|
||||
NotifyUnicastIpAddressChange((ushort)ADDRESS_FAMILY.AF_INET, Callback, null, new BOOLEAN(), ref handle);
|
||||
|
||||
if (CreateUnicastIpAddressEntry(&addr) != 0)
|
||||
{
|
||||
// ignored return state because i feel great
|
||||
CancelMibChangeNotify2(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
obj.WaitOne();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool RefreshIPTable(AddressFamily inet, ulong index);
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class tun2socks
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
TYPE_BYPBIND,
|
||||
TYPE_BYPLIST,
|
||||
TYPE_DNSADDR,
|
||||
TYPE_ADAPMTU,
|
||||
TYPE_TCPREST,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
TYPE_UDPREST,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
}
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Log.Verbose( $"[tun2socks] Dial {name}: {value}");
|
||||
return tun_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
{
|
||||
Log.Verbose("[tun2socks] init");
|
||||
return tun_init();
|
||||
}
|
||||
|
||||
public static async Task<bool> FreeAsync()
|
||||
{
|
||||
return await Task.Run(tun_free).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private const string tun2socks_bin = "tun2socks.bin";
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool tun_dial(NameList name, byte[] value);
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool tun_init();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool tun_free();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tun_luid();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong tun_getUP();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong tun_getDL();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
namespace Netch.Models
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class AioDNSConfig
|
||||
{
|
||||
public string ChinaDNS { get; set; } = $"tcp://{Constants.DefaultCNPrimaryDNS}";
|
||||
public string ChinaDNS { get; set; } = $"tcp://{Constants.DefaultCNPrimaryDNS}:53";
|
||||
|
||||
public string OtherDNS { get; set; } = $"tcp://{Constants.DefaultPrimaryDNS}";
|
||||
public string OtherDNS { get; set; } = $"tcp://{Constants.DefaultPrimaryDNS}:53";
|
||||
|
||||
public ushort ListenPort { get; set; } = 253;
|
||||
[JsonIgnore]
|
||||
public ushort ListenPort { get; set; } = 53;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
public bool DNSProxy { get; set; } = true;
|
||||
|
||||
public string DNSHost { get; set; } = Constants.DefaultPrimaryDNS;
|
||||
public string DNSHost { get; set; } = $"{Constants.DefaultPrimaryDNS}:53";
|
||||
|
||||
public int ICMPDelay { get; set; } = 10;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
public string HijackDNS { get; set; } = $"tcp://{Constants.DefaultPrimaryDNS}";
|
||||
public string DNS { get; set; } = Constants.DefaultPrimaryDNS;
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
|
||||
@@ -3,6 +3,11 @@ GetBestRoute
|
||||
GetExtendedTcpTable
|
||||
MIB_TCPTABLE_OWNER_PID
|
||||
ADDRESS_FAMILY
|
||||
MIB_UNICASTIPADDRESS_ROW
|
||||
InitializeUnicastIpAddressEntry
|
||||
CreateUnicastIpAddressEntry
|
||||
NotifyUnicastIpAddressChange
|
||||
CancelMibChangeNotify2
|
||||
|
||||
// User32.dll
|
||||
SetWindowPos
|
||||
@@ -16,6 +21,7 @@ GetConsoleWindow
|
||||
|
||||
// Ws2_32.dll
|
||||
ntohs
|
||||
inet_pton
|
||||
|
||||
// Windows.h
|
||||
// WIN32_ERROR
|
||||
@@ -152,7 +152,7 @@
|
||||
"Netmask": "子网掩码",
|
||||
"Gateway": "网关",
|
||||
"Use custom DNS": "使用自定义 DNS",
|
||||
"Proxy DNS in Proxy Rule IPs Mode": "在 代理规则IP 模式下代理 DNS",
|
||||
"Proxy DNS": "代理 DNS",
|
||||
"Exit when closed": "关闭时退出",
|
||||
"Stop when exited": "退出时停止",
|
||||
"Global Bypass IPs": "全局直连 IP",
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Netch.Services
|
||||
}
|
||||
}
|
||||
|
||||
private static void Sort()
|
||||
private static void SortCollection()
|
||||
{
|
||||
// TODO better sort need to discuss
|
||||
// TODO replace Mode Collection type
|
||||
@@ -82,6 +82,12 @@ namespace Netch.Services
|
||||
mode.WriteFile();
|
||||
}
|
||||
|
||||
public void Sort()
|
||||
{
|
||||
SortCollection();
|
||||
Global.MainForm.LoadModes();
|
||||
}
|
||||
|
||||
public static void Delete(Mode mode)
|
||||
{
|
||||
if (mode.FullName == null)
|
||||
|
||||
@@ -32,19 +32,14 @@ namespace Netch.Utils
|
||||
return Get((int)route.dwForwardIfIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="interfaceIndex"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <returns></returns>
|
||||
public static NetworkInterface Get(int interfaceIndex)
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces().First(n => n.GetIndex() == interfaceIndex);
|
||||
}
|
||||
|
||||
public static NetworkInterface Get(string description)
|
||||
public static NetworkInterface Get(Func<NetworkInterface, bool> expression)
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces().First(n => n.Description == description);
|
||||
return NetworkInterface.GetAllNetworkInterfaces().First(expression);
|
||||
}
|
||||
|
||||
public static void SetInterfaceMetric(int interfaceIndex, int? metric = null)
|
||||
|
||||
Reference in New Issue
Block a user