- Migrate to xjasonlyu/tun2socks

- Fix Starting Controller misc UI block
- Fix didn't stop Controller when starting Controller
This commit is contained in:
ChsBuffer
2021-11-10 21:51:37 +08:00
parent 066e33b4d3
commit 79c4a9d203
19 changed files with 210 additions and 207 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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>
/// 网关

View File

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

View File

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

View File

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

View File

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