From 635212f24de417867f16fbc09f0727086936ec69 Mon Sep 17 00:00:00 2001 From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com> Date: Fri, 10 Sep 2021 23:56:25 +0800 Subject: [PATCH] Replace NTTController with NatTypetester(Stun.Net) Enable NAT Type Test for all mode types Remove Shadowsocks SS --- Netch/Controllers/MainController.cs | 69 ++++++------ Netch/Controllers/NFController.cs | 9 +- Netch/Controllers/NTTController.cs | 106 ------------------ Netch/Controllers/PcapController.cs | 2 +- Netch/Controllers/TUNController.cs | 2 +- Netch/Enums/ModeFeature.cs | 5 +- Netch/Forms/MainForm.cs | 35 +++--- Netch/Forms/SettingForm.Designer.cs | 15 +-- Netch/Forms/SettingForm.cs | 2 - Netch/Interfaces/IModeController.cs | 3 +- Netch/Interfaces/IServerController.cs | 2 +- Netch/Models/NatTypeTestResult.cs | 9 ++ Netch/Models/Setting.cs | 9 +- Netch/Netch.csproj | 1 + Netch/Resources/zh-CN | 2 +- .../Shadowsocks/ShadowsocksController.cs | 2 +- .../ShadowsocksR/ShadowsocksRController.cs | 2 +- Netch/Servers/Socks5/Socks5Controller.cs | 2 +- Netch/Servers/Trojan/TrojanController.cs | 2 +- Netch/Servers/V2ray/V2rayController.cs | 2 +- Netch/Utils/ModeHelper.cs | 4 +- Netch/Utils/NatTypeTester.cs | 76 +++++++++++++ 22 files changed, 154 insertions(+), 207 deletions(-) delete mode 100644 Netch/Controllers/NTTController.cs create mode 100644 Netch/Models/NatTypeTestResult.cs create mode 100644 Netch/Utils/NatTypeTester.cs diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 8ad6a8fc..da26e6dd 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.Threading; @@ -14,9 +15,11 @@ namespace Netch.Controllers { public static class MainController { - public static Mode? Mode { get; private set; } + public static Socks5Server? Socks5Server { get; private set; } - public static readonly NTTController NTTController = new(); + public static Server? Server { get; private set; } + + public static Mode? Mode { get; private set; } public static IServerController? ServerController { get; private set; } @@ -31,12 +34,10 @@ namespace Netch.Controllers if (await DnsUtils.LookupAsync(server.Hostname) == null) throw new MessageException(i18N.Translate("Lookup Server hostname failed")); + Server = server; Mode = mode; - await Task.WhenAll( - Task.Run(NativeMethods.RefreshDNSCache), - Task.Run(Firewall.AddNetchFwRules) - ); + await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules)); if (Log.IsEnabled(LogEventLevel.Debug)) Task.Run(() => @@ -53,19 +54,34 @@ namespace Netch.Controllers if (modePort != null) TryReleaseTcpPort((ushort)modePort, portName); - switch (server) + + switch (Server) { - case Socks5Server socks5 when !socks5.Auth() || socks5.Auth() && ModeFeatures.HasFlag(ModeFeature.SupportSocks5Auth): - case ShadowsocksServer shadowsocks when !shadowsocks.HasPlugin() && ModeFeatures.HasFlag(ModeFeature.SupportShadowsocks) && - Global.Settings.Redirector.RedirectorSS: + case Socks5Server socks5 when !socks5.Auth(): + case Socks5Server socks5B when socks5B.Auth() && ModeFeatures.HasFlag(ModeFeature.SupportSocks5Auth): + // Directly Start ModeController + Socks5Server = (Socks5Server)Server; + Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name)); + await ModeController.StartAsync(Socks5Server, mode); break; default: - server = await StartServerAsync(server); + // Start Server Controller to get a local socks5 server + Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}"); + + ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController(); + Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name)); + + TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5"); + Socks5Server = await ServerController.StartAsync(server); + + StatusPortInfoText.Socks5Port = Socks5Server.Port; + StatusPortInfoText.UpdateShareLan(); + + // Start Mode Controller + Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name)); + await ModeController.StartAsync(Socks5Server, mode); break; } - - Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name)); - await ModeController.StartAsync(server, mode); } catch (Exception e) { @@ -86,23 +102,6 @@ namespace Netch.Controllers } } - private static async Task StartServerAsync(Server server) - { - ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController(); - - TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5"); - - Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name)); - - Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}"); - var socks5Bridge = await ServerController.StartAsync(server); - - StatusPortInfoText.Socks5Port = socks5Bridge.Port; - StatusPortInfoText.UpdateShareLan(); - - return socks5Bridge; - } - public static async Task StopAsync() { if (ServerController == null && ModeController == null) @@ -111,8 +110,6 @@ namespace Netch.Controllers Log.Information("Stop Main Controller"); StatusPortInfoText.Reset(); - Task.Run(() => NTTController.StopAsync()).Forget(); - var tasks = new[] { Task.Run(() => ServerController?.StopAsync()), @@ -170,5 +167,11 @@ namespace Netch.Controllers PortCheck(port, portName, PortType.TCP); } + + public static async Task NatTestAsync() + { + Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null"); + return await NatTypeTester.StartAsync(Socks5Server); + } } } \ No newline at end of file diff --git a/Netch/Controllers/NFController.cs b/Netch/Controllers/NFController.cs index 3c6f4ed6..333fcdc9 100644 --- a/Netch/Controllers/NFController.cs +++ b/Netch/Controllers/NFController.cs @@ -27,7 +27,7 @@ namespace Netch.Controllers public string Name => "Redirector"; - public async Task StartAsync(Server server, Mode mode) + public async Task StartAsync(Socks5Server server, Mode mode) { _server = server; _mode = mode; @@ -122,13 +122,6 @@ namespace Netch.Controllers Dial(NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty); Dial(NameList.TYPE_TCPMETH + offset, string.Empty); } - else if (server is ShadowsocksServer shadowsocks && !shadowsocks.HasPlugin() && _rdrConfig.RedirectorSS) - { - Dial(NameList.TYPE_TCPTYPE + offset, "Shadowsocks"); - Dial(NameList.TYPE_TCPHOST + offset, $"{await shadowsocks.AutoResolveHostnameAsync()}:{shadowsocks.Port}"); - Dial(NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod); - Dial(NameList.TYPE_TCPPASS + offset, shadowsocks.Password); - } else { Trace.Assert(false); diff --git a/Netch/Controllers/NTTController.cs b/Netch/Controllers/NTTController.cs deleted file mode 100644 index b03e7828..00000000 --- a/Netch/Controllers/NTTController.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Netch.Interfaces; -using Netch.Utils; -using Serilog; - -namespace Netch.Controllers -{ - public class NTTController : Guard, IController - { - public NTTController() : base("NTT.exe") - { - } - - public override string Name => "NTT"; - - /// - /// 启动 NatTypeTester - /// - /// - public async Task<(string? result, string? localEnd, string? publicEnd)> StartAsync() - { - string? localEnd = null, publicEnd = null, result = null, bindingTest = null; - - try - { - Instance.StartInfo.Arguments = $" {Global.Settings.STUN_Server} {Global.Settings.STUN_Server_Port}"; - Instance.Start(); - - var output = await Instance.StandardOutput.ReadToEndAsync(); - var error = await Instance.StandardError.ReadToEndAsync(); - - try - { - await File.WriteAllTextAsync(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), $"{output}\r\n{error}"); - } - catch (Exception e) - { - Log.Warning(e, "写入 {Name} 日志错误", Name); - } - - if (output.IsNullOrWhiteSpace()) - { - if (error.IsNullOrWhiteSpace()) - { - Log.Warning("NTT no output"); - return (null, null, null); - } - - var errorFirst = error.GetLines().First(); - return (errorFirst.SplitTrimEntries(':').Last(), null, null); - } - - foreach (var line in output.Split('\n')) - { - var str = line.SplitTrimEntries(':'); - if (str.Length < 2) - continue; - - var key = str[0]; - var value = str[1]; - switch (key) - { - case "Other address is": - case "Nat mapping behavior": - case "Nat filtering behavior": - break; - case "Binding test": - bindingTest = value; - break; - case "Local address": - localEnd = value; - break; - case "Mapped address": - publicEnd = value; - break; - case "result": - result = value; - break; - } - } - - if (bindingTest == "Fail") - result = "Fail"; - - return (result, localEnd, publicEnd); - } - catch (Exception e) - { - Log.Error(e, "{Name} 控制器启动异常", Name); - try - { - await StopAsync(); - } - catch - { - // ignored - } - - return (null, null, null); - } - } - } -} \ No newline at end of file diff --git a/Netch/Controllers/PcapController.cs b/Netch/Controllers/PcapController.cs index 4bf42220..5063b642 100644 --- a/Netch/Controllers/PcapController.cs +++ b/Netch/Controllers/PcapController.cs @@ -31,7 +31,7 @@ namespace Netch.Controllers public override string Name => "pcap2socks"; - public async Task StartAsync(Server server, Mode mode) + public async Task StartAsync(Socks5Server server, Mode mode) { _server = server; _mode = mode; diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index e3ba1c8f..1112e02b 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -30,7 +30,7 @@ namespace Netch.Controllers public string Name => "tun2socks"; - public async Task StartAsync(Server server, Mode mode) + public async Task StartAsync(Socks5Server server, Mode mode) { _mode = mode; _tunConfig = Global.Settings.TUNTAP; diff --git a/Netch/Enums/ModeFeature.cs b/Netch/Enums/ModeFeature.cs index bdc655c2..01b82f9d 100644 --- a/Netch/Enums/ModeFeature.cs +++ b/Netch/Enums/ModeFeature.cs @@ -8,9 +8,6 @@ namespace Netch.Enums SupportSocks5 = 0, SupportIPv4 = 0, SupportSocks5Auth = 0b_0001, - [Obsolete] - SupportShadowsocks = 0b_0010, - SupportIPv6 = 0b_0100, - RequireTestNat = 0b_1000 + SupportIPv6 = 0b_0100 } } \ No newline at end of file diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index 4e1b9f7e..95504ec9 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.IO; using System.Linq; -using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Windows.Win32; @@ -1151,44 +1150,38 @@ namespace Netch.Forms private async void NatTypeStatusLabel_Click(object sender, EventArgs e) { - if (_state == State.Started && NatTestLock.CurrentCount != 0) - await NatTestAsync(); + await NatTestAsync(); } - private static readonly SemaphoreSlim NatTestLock = new(1, 1); - /// /// 测试 NAT /// private async Task NatTestAsync() { - if (!MainController.ModeFeatures.HasFlag(ModeFeature.RequireTestNat)) - return; - - if (NatTestLock.CurrentCount == 0) - return; - - await NatTestLock.WaitAsync(); - + NatTypeStatusLabel.Enabled = false; try { - NatTypeStatusText(i18N.Translate("Testing NAT")); + NatTypeStatusText(i18N.Translate("Testing NAT Type")); - var (result, _, publicEnd) = await MainController.NTTController.StartAsync(); + var res = await MainController.NatTestAsync(); - if (!string.IsNullOrEmpty(publicEnd)) + if (!string.IsNullOrEmpty(res.PublicEnd)) { - var country = await Utils.Utils.GetCityCodeAsync(publicEnd!); - NatTypeStatusText(result, country); + var country = await Utils.Utils.GetCityCodeAsync(res.PublicEnd); + NatTypeStatusText(res.Result, country); } else { - NatTypeStatusText(result ?? "Error"); + NatTypeStatusText(res.Result ?? "Error"); } } + catch (Exception e) + { + NatTypeStatusText(e.Message); + } finally { - NatTestLock.Release(); + NatTypeStatusLabel.Enabled = true; } } @@ -1466,4 +1459,4 @@ namespace Netch.Forms #endregion } -} +} \ No newline at end of file diff --git a/Netch/Forms/SettingForm.Designer.cs b/Netch/Forms/SettingForm.Designer.cs index 415dfe74..0c6f2a34 100644 --- a/Netch/Forms/SettingForm.Designer.cs +++ b/Netch/Forms/SettingForm.Designer.cs @@ -61,7 +61,6 @@ namespace Netch.Forms this.FilterICMPCheckBox = new System.Windows.Forms.CheckBox(); this.ICMPDelayLabel = new System.Windows.Forms.Label(); this.ICMPDelayTextBox = new System.Windows.Forms.TextBox(); - this.RedirectorSSCheckBox = 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(); @@ -362,7 +361,6 @@ namespace Netch.Forms this.NFTabPage.Controls.Add(this.FilterICMPCheckBox); this.NFTabPage.Controls.Add(this.ICMPDelayLabel); this.NFTabPage.Controls.Add(this.ICMPDelayTextBox); - this.NFTabPage.Controls.Add(this.RedirectorSSCheckBox); this.NFTabPage.Controls.Add(this.ChildProcessHandleCheckBox); this.NFTabPage.Location = new System.Drawing.Point(4, 29); this.NFTabPage.Name = "NFTabPage"; @@ -436,21 +434,11 @@ namespace Netch.Forms this.ICMPDelayTextBox.TabIndex = 6; this.ICMPDelayTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; // - // RedirectorSSCheckBox - // - this.RedirectorSSCheckBox.AutoSize = true; - this.RedirectorSSCheckBox.Location = new System.Drawing.Point(15, 140); - this.RedirectorSSCheckBox.Name = "RedirectorSSCheckBox"; - this.RedirectorSSCheckBox.Size = new System.Drawing.Size(265, 21); - this.RedirectorSSCheckBox.TabIndex = 7; - this.RedirectorSSCheckBox.Text = "Redirector built-in Shadowsocks support"; - this.RedirectorSSCheckBox.UseVisualStyleBackColor = true; - // // ChildProcessHandleCheckBox // this.ChildProcessHandleCheckBox.AutoSize = true; this.ChildProcessHandleCheckBox.Enabled = false; - this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(15, 170); + this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(15, 140); this.ChildProcessHandleCheckBox.Name = "ChildProcessHandleCheckBox"; this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(150, 21); this.ChildProcessHandleCheckBox.TabIndex = 8; @@ -1082,7 +1070,6 @@ namespace Netch.Forms private System.Windows.Forms.TextBox OtherDNSTextBox; private System.Windows.Forms.TextBox ChinaDNSTextBox; private System.Windows.Forms.TextBox DNSHijackHostTextBox; - private System.Windows.Forms.CheckBox RedirectorSSCheckBox; private System.Windows.Forms.Label ServerPingTypeLabel; private System.Windows.Forms.RadioButton TCPingRadioBtn; private System.Windows.Forms.RadioButton ICMPingRadioBtn; diff --git a/Netch/Forms/SettingForm.cs b/Netch/Forms/SettingForm.cs index 352f2f8c..821e2640 100644 --- a/Netch/Forms/SettingForm.cs +++ b/Netch/Forms/SettingForm.cs @@ -112,8 +112,6 @@ namespace Netch.Forms BindTextBox(ICMPDelayTextBox, s => int.TryParse(s, out _), s => { }, Global.Settings.Redirector.ICMPDelay); - BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.Redirector.RedirectorSS = s, Global.Settings.Redirector.RedirectorSS); - BindCheckBox(ChildProcessHandleCheckBox, s => Global.Settings.Redirector.ChildProcessHandle = s, Global.Settings.Redirector.ChildProcessHandle); diff --git a/Netch/Interfaces/IModeController.cs b/Netch/Interfaces/IModeController.cs index 4577c67e..3ceedf8b 100644 --- a/Netch/Interfaces/IModeController.cs +++ b/Netch/Interfaces/IModeController.cs @@ -1,10 +1,11 @@ using System.Threading.Tasks; using Netch.Models; +using Netch.Servers; namespace Netch.Interfaces { public interface IModeController : IController { - public Task StartAsync(Server server, Mode mode); + public Task StartAsync(Socks5Server server, Mode mode); } } \ No newline at end of file diff --git a/Netch/Interfaces/IServerController.cs b/Netch/Interfaces/IServerController.cs index 33a582b3..2f06121f 100644 --- a/Netch/Interfaces/IServerController.cs +++ b/Netch/Interfaces/IServerController.cs @@ -10,7 +10,7 @@ namespace Netch.Interfaces public string? LocalAddress { get; set; } - public Task StartAsync(Server s); + public Task StartAsync(Server s); } public static class ServerControllerExtension diff --git a/Netch/Models/NatTypeTestResult.cs b/Netch/Models/NatTypeTestResult.cs new file mode 100644 index 00000000..3e262cce --- /dev/null +++ b/Netch/Models/NatTypeTestResult.cs @@ -0,0 +1,9 @@ +namespace Netch.Models +{ + public struct NatTypeTestResult + { + public string? Result; + public string? LocalEnd; + public string? PublicEnd; + } +} \ No newline at end of file diff --git a/Netch/Models/Setting.cs b/Netch/Models/Setting.cs index e3d054f9..c92c5ceb 100644 --- a/Netch/Models/Setting.cs +++ b/Netch/Models/Setting.cs @@ -1,6 +1,6 @@ -using Netch.Utils; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text.Json.Serialization; +using Netch.Utils; namespace Netch.Models { @@ -106,11 +106,6 @@ namespace Netch.Models public bool FilterICMP { get; set; } = false; - /// - /// 是否使用RDR内置SS - /// - public bool RedirectorSS { get; set; } = false; - /// /// 是否代理子进程 /// diff --git a/Netch/Netch.csproj b/Netch/Netch.csproj index 21531869..0ca39071 100644 --- a/Netch/Netch.csproj +++ b/Netch/Netch.csproj @@ -47,6 +47,7 @@ + diff --git a/Netch/Resources/zh-CN b/Netch/Resources/zh-CN index 873b0bc4..3b42f7e0 100644 --- a/Netch/Resources/zh-CN +++ b/Netch/Resources/zh-CN @@ -15,7 +15,7 @@ "Stopping": "正在停止中", "Stopped": "已停止", "Starting {0}": "正在启动 {0}", - "Testing NAT": "正在测试 NAT", + "Testing NAT Type": "正在测试 NAT 类型", "Setup Route Table Rule": "配置路由规则", "Test failed": "测试失败", "Starting update subscription": "正在更新订阅", diff --git a/Netch/Servers/Shadowsocks/ShadowsocksController.cs b/Netch/Servers/Shadowsocks/ShadowsocksController.cs index a33279e7..6c4f1709 100644 --- a/Netch/Servers/Shadowsocks/ShadowsocksController.cs +++ b/Netch/Servers/Shadowsocks/ShadowsocksController.cs @@ -23,7 +23,7 @@ namespace Netch.Servers public string? LocalAddress { get; set; } - public async Task StartAsync(Server s) + public async Task StartAsync(Server s) { var server = (ShadowsocksServer)s; diff --git a/Netch/Servers/ShadowsocksR/ShadowsocksRController.cs b/Netch/Servers/ShadowsocksR/ShadowsocksRController.cs index f4e91876..52dcaf94 100644 --- a/Netch/Servers/ShadowsocksR/ShadowsocksRController.cs +++ b/Netch/Servers/ShadowsocksR/ShadowsocksRController.cs @@ -23,7 +23,7 @@ namespace Netch.Servers public string? LocalAddress { get; set; } - public async Task StartAsync(Server s) + public async Task StartAsync(Server s) { var server = (ShadowsocksRServer)s; diff --git a/Netch/Servers/Socks5/Socks5Controller.cs b/Netch/Servers/Socks5/Socks5Controller.cs index bc5bc637..aedf5fc8 100644 --- a/Netch/Servers/Socks5/Socks5Controller.cs +++ b/Netch/Servers/Socks5/Socks5Controller.cs @@ -8,7 +8,7 @@ namespace Netch.Servers { public override string Name { get; } = "Socks5"; - public override async Task StartAsync(Server s) + public override async Task StartAsync(Server s) { var server = (Socks5Server)s; if (!server.Auth()) diff --git a/Netch/Servers/Trojan/TrojanController.cs b/Netch/Servers/Trojan/TrojanController.cs index 5f328a86..e575ef2b 100644 --- a/Netch/Servers/Trojan/TrojanController.cs +++ b/Netch/Servers/Trojan/TrojanController.cs @@ -26,7 +26,7 @@ namespace Netch.Servers public string? LocalAddress { get; set; } - public async Task StartAsync(Server s) + public async Task StartAsync(Server s) { var server = (TrojanServer)s; var trojanConfig = new TrojanConfig diff --git a/Netch/Servers/V2ray/V2rayController.cs b/Netch/Servers/V2ray/V2rayController.cs index 79c106ea..74369b0f 100644 --- a/Netch/Servers/V2ray/V2rayController.cs +++ b/Netch/Servers/V2ray/V2rayController.cs @@ -27,7 +27,7 @@ namespace Netch.Servers public string? LocalAddress { get; set; } - public virtual async Task StartAsync(Server s) + public virtual async Task StartAsync(Server s) { await using (var fileStream = new FileStream(Constants.TempConfig, FileMode.Create, FileAccess.Write, FileShare.Read)) { diff --git a/Netch/Utils/ModeHelper.cs b/Netch/Utils/ModeHelper.cs index 777fd385..a38ad612 100644 --- a/Netch/Utils/ModeHelper.cs +++ b/Netch/Utils/ModeHelper.cs @@ -131,11 +131,11 @@ namespace Netch.Utils switch (type) { case ModeType.Process: - return (new NFController(), ModeFeature.SupportIPv6 | ModeFeature.SupportSocks5Auth | ModeFeature.RequireTestNat); + return (new NFController(), ModeFeature.SupportIPv6 | ModeFeature.SupportSocks5Auth); case ModeType.ProxyRuleIPs: return (new TUNController(), ModeFeature.SupportSocks5Auth); case ModeType.BypassRuleIPs: - return (new TUNController(), ModeFeature.SupportSocks5Auth | ModeFeature.RequireTestNat); + return (new TUNController(), ModeFeature.SupportSocks5Auth); case ModeType.Pcap2Socks: return (new PcapController(), 0); default: diff --git a/Netch/Utils/NatTypeTester.cs b/Netch/Utils/NatTypeTester.cs new file mode 100644 index 00000000..dfed2715 --- /dev/null +++ b/Netch/Utils/NatTypeTester.cs @@ -0,0 +1,76 @@ +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Netch.Models; +using Netch.Servers; +using Socks5.Models; +using STUN.Client; +using STUN.Enums; +using STUN.Proxy; +using STUN.StunResult; + +namespace Netch.Utils +{ + public static class NatTypeTester + { + public static async Task StartAsync(Socks5Server socks5, CancellationToken ctx = default) + { + var stunServer = Global.Settings.STUN_Server; + var port = (ushort)Global.Settings.STUN_Server_Port; + var local = new IPEndPoint(IPAddress.Any, 0); + + var socks5Option = new Socks5CreateOption + { + Address = await DnsUtils.LookupAsync(socks5.Hostname), + Port = socks5.Port, + UsernamePassword = new UsernamePassword + { + UserName = socks5.Username, + Password = socks5.Password + } + }; + + var ip = await DnsUtils.LookupAsync(stunServer) ?? throw new MessageException("Wrong STUN Server!"); + + using IUdpProxy proxy = ProxyFactory.CreateProxy(ProxyType.Socks5, new IPEndPoint(IPAddress.Loopback, 0), socks5Option); + using var client = new StunClient5389UDP(new IPEndPoint(ip, port), local, proxy); + + await client.ConnectProxyAsync(ctx); + try + { + await client.QueryAsync(ctx); + } + finally + { + await client.CloseProxyAsync(ctx); + } + + var res = client.State; + var result = GetSimpleResult(res); + + return new NatTypeTestResult + { + Result = result, + LocalEnd = res.LocalEndPoint?.ToString(), + PublicEnd = res.PublicEndPoint?.ToString() + }; + } + + private static string GetSimpleResult(StunResult5389 res) + { + switch (res.BindingTestResult, res.MappingBehavior, res.FilteringBehavior) + { + case (not BindingTestResult.Success, _, _): + return res.BindingTestResult.ToString(); + case (_, MappingBehavior.Direct or MappingBehavior.EndpointIndependent, FilteringBehavior.EndpointIndependent): + return "1"; + case (_, MappingBehavior.Direct or MappingBehavior.EndpointIndependent, _): + return "2"; + case (_, MappingBehavior.AddressDependent or MappingBehavior.AddressAndPortDependent, _): + return "3"; + default: + return res.FilteringBehavior.ToString(); + } + } + } +} \ No newline at end of file