mirror of
https://github.com/netchx/netch.git
synced 2026-05-07 22:44:03 +08:00
✨ 添加NAT检测功能,特别感谢@HMBSbige大佬的轮子
This commit is contained in:
@@ -51,25 +51,30 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
public TUNTAPController pTUNTAPController;
|
||||
|
||||
/// <summary>
|
||||
/// NTT 控制器
|
||||
/// </summary>
|
||||
public NTTController pNTTController;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
public (bool, string) Start(Models.Server server, Models.Mode mode)
|
||||
{
|
||||
var result = false;
|
||||
var result = (false, "");
|
||||
switch (server.Type)
|
||||
{
|
||||
case "Socks5":
|
||||
if (mode.Type == 4)
|
||||
{
|
||||
result = false;
|
||||
result = (false, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
result = (true, null);
|
||||
}
|
||||
break;
|
||||
case "SS":
|
||||
@@ -78,7 +83,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
pSSController = new SSController();
|
||||
}
|
||||
result = pSSController.Start(server, mode);
|
||||
result = (pSSController.Start(server, mode), null);
|
||||
break;
|
||||
case "SSR":
|
||||
KillProcess("ShadowsocksR");
|
||||
@@ -86,7 +91,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
pSSRController = new SSRController();
|
||||
}
|
||||
result = pSSRController.Start(server, mode);
|
||||
result = (pSSRController.Start(server, mode), null);
|
||||
break;
|
||||
case "VMess":
|
||||
KillProcess("v2ray");
|
||||
@@ -94,11 +99,11 @@ namespace Netch.Controllers
|
||||
{
|
||||
pVMessController = new VMessController();
|
||||
}
|
||||
result = pVMessController.Start(server, mode);
|
||||
result = (pVMessController.Start(server, mode), null);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
if (result.Item1)
|
||||
{
|
||||
if (mode.Type == 0)
|
||||
{
|
||||
@@ -106,8 +111,12 @@ namespace Netch.Controllers
|
||||
{
|
||||
pNFController = new NFController();
|
||||
}
|
||||
if (pNTTController == null)
|
||||
{
|
||||
pNTTController = new NTTController();
|
||||
}
|
||||
// 进程代理模式,启动 NF 控制器
|
||||
result = pNFController.Start(server, mode);
|
||||
result = (pNFController.Start(server, mode), pNTTController.Start().Item2);
|
||||
}
|
||||
else if (mode.Type == 1)
|
||||
{
|
||||
@@ -115,8 +124,12 @@ namespace Netch.Controllers
|
||||
{
|
||||
pTUNTAPController = new TUNTAPController();
|
||||
}
|
||||
if (pNTTController == null)
|
||||
{
|
||||
pNTTController = new NTTController();
|
||||
}
|
||||
// TUN/TAP 黑名单代理模式,启动 TUN/TAP 控制器
|
||||
result = pTUNTAPController.Start(server, mode);
|
||||
result = (pTUNTAPController.Start(server, mode), pNTTController.Start().Item2);
|
||||
}
|
||||
else if (mode.Type == 2)
|
||||
{
|
||||
@@ -124,8 +137,12 @@ namespace Netch.Controllers
|
||||
{
|
||||
pTUNTAPController = new TUNTAPController();
|
||||
}
|
||||
if (pNTTController == null)
|
||||
{
|
||||
pNTTController = new NTTController();
|
||||
}
|
||||
// TUN/TAP 白名单代理模式,启动 TUN/TAP 控制器
|
||||
result = pTUNTAPController.Start(server, mode);
|
||||
result = (pTUNTAPController.Start(server, mode), pNTTController.Start().Item2);
|
||||
}
|
||||
else if (mode.Type == 3 || mode.Type == 5)
|
||||
{
|
||||
@@ -134,7 +151,7 @@ namespace Netch.Controllers
|
||||
pHTTPController = new HTTPController();
|
||||
}
|
||||
// HTTP 系统代理和 Socks5 和 HTTP 代理模式,启动 HTTP 控制器
|
||||
result = pHTTPController.Start(server, mode);
|
||||
result = (pHTTPController.Start(server, mode), null);
|
||||
}
|
||||
else if (mode.Type == 4)
|
||||
{
|
||||
@@ -142,11 +159,11 @@ namespace Netch.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
result = (false, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
if (!result.Item1)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
@@ -171,7 +188,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
pVMessController.Stop();
|
||||
}
|
||||
|
||||
|
||||
if (pNFController != null)
|
||||
{
|
||||
pNFController.Stop();
|
||||
@@ -184,10 +201,15 @@ namespace Netch.Controllers
|
||||
{
|
||||
pHTTPController.Stop();
|
||||
}
|
||||
|
||||
|
||||
if (pNTTController != null)
|
||||
{
|
||||
pNTTController.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void KillProcess(string name) {
|
||||
public void KillProcess(string name)
|
||||
{
|
||||
var processes = Process.GetProcessesByName(name);
|
||||
foreach (var p in processes)
|
||||
{
|
||||
@@ -198,7 +220,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsChildProcess(Process process,string name)
|
||||
private static bool IsChildProcess(Process process, string name)
|
||||
{
|
||||
bool result;
|
||||
try
|
||||
|
||||
@@ -114,6 +114,8 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
var processes = "";
|
||||
|
||||
mode.Rule.Add("NTT.exe");
|
||||
foreach (var proc in mode.Rule)
|
||||
{
|
||||
processes += proc;
|
||||
|
||||
93
Netch/Controllers/NTTController.cs
Normal file
93
Netch/Controllers/NTTController.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class NTTController
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 启动NatTypeTester
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (bool, string, string, string) Start()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists("bin\\NTT.exe"))
|
||||
{
|
||||
return (false, null, null, null);
|
||||
}
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\NTT.exe";
|
||||
|
||||
Instance.StartInfo.Arguments = $" {Global.Settings.STUN_Server} {Global.Settings.STUN_Server_Port}";
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = Models.State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
Instance.WaitForExit();
|
||||
|
||||
string[] result = File.ReadAllText("logging\\NTT.log").ToString().Split('#');
|
||||
var natType = result[0];
|
||||
var localEnd = result[1];
|
||||
var publicEnd = result[2];
|
||||
|
||||
return (true, natType, localEnd, publicEnd);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Utils.Logging.Info("NTT 进程出错");
|
||||
Stop();
|
||||
return (false, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
if (File.Exists("logging\\NTT.log"))
|
||||
{
|
||||
File.Delete("logging\\NTT.log");
|
||||
}
|
||||
File.AppendAllText("logging\\NTT.log", $"{e.Data}\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Netch/Forms/MainForm.Designer.cs
generated
11
Netch/Forms/MainForm.Designer.cs
generated
@@ -78,6 +78,7 @@ namespace Netch.Forms
|
||||
this.SettingsButton = new System.Windows.Forms.Button();
|
||||
this.ProfileGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.NatTypeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.MenuStrip.SuspendLayout();
|
||||
this.ConfigurationGroupBox.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.CopyLinkPictureBox)).BeginInit();
|
||||
@@ -421,7 +422,8 @@ namespace Netch.Forms
|
||||
this.StatusLabel,
|
||||
this.UsedBandwidthLabel,
|
||||
this.DownloadSpeedLabel,
|
||||
this.UploadSpeedLabel});
|
||||
this.UploadSpeedLabel,
|
||||
this.NatTypeStatusLabel});
|
||||
this.StatusStrip.Location = new System.Drawing.Point(0, 254);
|
||||
this.StatusStrip.Name = "StatusStrip";
|
||||
this.StatusStrip.Size = new System.Drawing.Size(629, 22);
|
||||
@@ -534,6 +536,12 @@ namespace Netch.Forms
|
||||
this.ProfileTable.Size = new System.Drawing.Size(599, 43);
|
||||
this.ProfileTable.TabIndex = 0;
|
||||
//
|
||||
// NatTypeStatusLabel
|
||||
//
|
||||
this.NatTypeStatusLabel.Name = "NatTypeStatusLabel";
|
||||
this.NatTypeStatusLabel.Size = new System.Drawing.Size(109, 17);
|
||||
this.NatTypeStatusLabel.Text = "";
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
@@ -623,5 +631,6 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.PictureBox EditModePictureBox;
|
||||
private System.Windows.Forms.PictureBox DeleteModePictureBox;
|
||||
private System.Windows.Forms.PictureBox CopyLinkPictureBox;
|
||||
private System.Windows.Forms.ToolStripStatusLabel NatTypeStatusLabel;
|
||||
}
|
||||
}
|
||||
@@ -556,6 +556,7 @@ namespace Netch.Forms
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
|
||||
ControlButton.Text = Utils.i18N.Translate("Start");
|
||||
MainController.Stop();
|
||||
NatTypeStatusLabel.Text = "";
|
||||
}
|
||||
Utils.Configuration.Save();
|
||||
}).ContinueWith(task =>
|
||||
@@ -786,7 +787,18 @@ namespace Netch.Forms
|
||||
var mode = ModeComboBox.SelectedItem as Models.Mode;
|
||||
|
||||
MainController = new MainController();
|
||||
if (MainController.Start(server, mode))
|
||||
|
||||
var startResult = MainController.Start(server, mode);//item1是否启动成功,item2nat类型
|
||||
if (startResult.Item2 != null)
|
||||
{
|
||||
NatTypeStatusLabel.Text = "NatType:" + startResult.Item2;
|
||||
}
|
||||
else
|
||||
{
|
||||
NatTypeStatusLabel.Text = "";
|
||||
}
|
||||
|
||||
if (startResult.Item1)
|
||||
{
|
||||
// UsedBandwidthLabel.Visible = UploadSpeedLabel.Visible = DownloadSpeedLabel.Visible = true;
|
||||
// MainController.pNFController.OnBandwidthUpdated += OnBandwidthUpdated;
|
||||
@@ -883,6 +895,7 @@ namespace Netch.Forms
|
||||
var mode = ModeComboBox.SelectedItem as Models.Mode;
|
||||
|
||||
MainController.Stop();
|
||||
NatTypeStatusLabel.Text = "";
|
||||
|
||||
// LastUploadBandwidth = 0;
|
||||
// LastDownloadBandwidth = 0;
|
||||
|
||||
54
Netch/Forms/SettingForm.Designer.cs
generated
54
Netch/Forms/SettingForm.Designer.cs
generated
@@ -58,6 +58,10 @@
|
||||
this.StartWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.StopWhenExitedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ExitWhenClosedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.STUN_ServerTextBox = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.STUN_ServerPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.PortGroupBox.SuspendLayout();
|
||||
this.TUNTAPGroupBox.SuspendLayout();
|
||||
this.BehaviorGroupBox.SuspendLayout();
|
||||
@@ -241,7 +245,7 @@
|
||||
// ControlButton
|
||||
//
|
||||
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ControlButton.Location = new System.Drawing.Point(357, 549);
|
||||
this.ControlButton.Location = new System.Drawing.Point(357, 648);
|
||||
this.ControlButton.Name = "ControlButton";
|
||||
this.ControlButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ControlButton.TabIndex = 11;
|
||||
@@ -252,7 +256,7 @@
|
||||
// GlobalBypassIPsButton
|
||||
//
|
||||
this.GlobalBypassIPsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.GlobalBypassIPsButton.Location = new System.Drawing.Point(12, 549);
|
||||
this.GlobalBypassIPsButton.Location = new System.Drawing.Point(12, 648);
|
||||
this.GlobalBypassIPsButton.Name = "GlobalBypassIPsButton";
|
||||
this.GlobalBypassIPsButton.Size = new System.Drawing.Size(128, 23);
|
||||
this.GlobalBypassIPsButton.TabIndex = 10;
|
||||
@@ -262,7 +266,11 @@
|
||||
//
|
||||
// BehaviorGroupBox
|
||||
//
|
||||
this.BehaviorGroupBox.Controls.Add(this.STUN_ServerPortTextBox);
|
||||
this.BehaviorGroupBox.Controls.Add(this.label2);
|
||||
this.BehaviorGroupBox.Controls.Add(this.label1);
|
||||
this.BehaviorGroupBox.Controls.Add(this.RunAtStartup);
|
||||
this.BehaviorGroupBox.Controls.Add(this.STUN_ServerTextBox);
|
||||
this.BehaviorGroupBox.Controls.Add(this.MinimizeWhenStartedCheckBox);
|
||||
this.BehaviorGroupBox.Controls.Add(this.ProfileCount_Label);
|
||||
this.BehaviorGroupBox.Controls.Add(this.ProfileCount_TextBox);
|
||||
@@ -272,7 +280,7 @@
|
||||
this.BehaviorGroupBox.Controls.Add(this.ExitWhenClosedCheckBox);
|
||||
this.BehaviorGroupBox.Location = new System.Drawing.Point(12, 330);
|
||||
this.BehaviorGroupBox.Name = "BehaviorGroupBox";
|
||||
this.BehaviorGroupBox.Size = new System.Drawing.Size(420, 213);
|
||||
this.BehaviorGroupBox.Size = new System.Drawing.Size(420, 312);
|
||||
this.BehaviorGroupBox.TabIndex = 8;
|
||||
this.BehaviorGroupBox.TabStop = false;
|
||||
this.BehaviorGroupBox.Text = "Behavior";
|
||||
@@ -358,11 +366,45 @@
|
||||
this.ExitWhenClosedCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.ExitWhenClosedCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(9, 214);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(82, 17);
|
||||
this.label1.TabIndex = 10;
|
||||
this.label1.Text = "STUN Server";
|
||||
//
|
||||
// STUN_ServerTextBox
|
||||
//
|
||||
this.STUN_ServerTextBox.Location = new System.Drawing.Point(120, 211);
|
||||
this.STUN_ServerTextBox.Name = "STUN_ServerTextBox";
|
||||
this.STUN_ServerTextBox.Size = new System.Drawing.Size(294, 23);
|
||||
this.STUN_ServerTextBox.TabIndex = 11;
|
||||
this.STUN_ServerTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(9, 243);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(110, 17);
|
||||
this.label2.TabIndex = 12;
|
||||
this.label2.Text = "STUN Server Port";
|
||||
//
|
||||
// STUN_ServerPortTextBox
|
||||
//
|
||||
this.STUN_ServerPortTextBox.Location = new System.Drawing.Point(120, 237);
|
||||
this.STUN_ServerPortTextBox.Name = "STUN_ServerPortTextBox";
|
||||
this.STUN_ServerPortTextBox.Size = new System.Drawing.Size(294, 23);
|
||||
this.STUN_ServerPortTextBox.TabIndex = 8;
|
||||
this.STUN_ServerPortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// SettingForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(444, 583);
|
||||
this.ClientSize = new System.Drawing.Size(444, 682);
|
||||
this.Controls.Add(this.BehaviorGroupBox);
|
||||
this.Controls.Add(this.PortGroupBox);
|
||||
this.Controls.Add(this.GlobalBypassIPsButton);
|
||||
@@ -419,5 +461,9 @@
|
||||
private System.Windows.Forms.TextBox ProfileCount_TextBox;
|
||||
private System.Windows.Forms.CheckBox MinimizeWhenStartedCheckBox;
|
||||
private System.Windows.Forms.CheckBox RunAtStartup;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox STUN_ServerTextBox;
|
||||
private System.Windows.Forms.TextBox STUN_ServerPortTextBox;
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,8 @@ namespace Netch.Forms
|
||||
ProfileCount_Label.Text = Utils.i18N.Translate(ProfileCount_Label.Text);
|
||||
|
||||
ProfileCount_TextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
STUN_ServerTextBox.Text = Global.Settings.STUN_Server.ToString();
|
||||
STUN_ServerPortTextBox.Text = Global.Settings.STUN_Server_Port.ToString();
|
||||
|
||||
if (Global.Settings.TUNTAP.DNS.Count > 0)
|
||||
{
|
||||
@@ -289,7 +291,7 @@ namespace Netch.Forms
|
||||
{
|
||||
var ProfileCount = int.Parse(ProfileCount_TextBox.Text);
|
||||
|
||||
if (ProfileCount>0)
|
||||
if (ProfileCount > 0)
|
||||
{
|
||||
Global.Settings.ProfileCount = ProfileCount;
|
||||
}
|
||||
@@ -305,6 +307,29 @@ namespace Netch.Forms
|
||||
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var STUN_Server = STUN_ServerTextBox.Text;
|
||||
Global.Settings.STUN_Server = STUN_Server;
|
||||
|
||||
var STUN_ServerPort = int.Parse(STUN_ServerPortTextBox.Text);
|
||||
|
||||
if (STUN_ServerPort > 0)
|
||||
{
|
||||
Global.Settings.STUN_Server_Port = STUN_ServerPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCount_TextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBox.Show(Utils.i18N.Translate("STUN_ServerPort value illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Global.Settings.TUNTAP.Address = TUNTAPAddressTextBox.Text;
|
||||
Global.Settings.TUNTAP.Netmask = TUNTAPNetmaskTextBox.Text;
|
||||
|
||||
@@ -138,5 +138,15 @@ namespace Netch.Models
|
||||
/// 快捷配置数量
|
||||
/// </summary>
|
||||
public int ProfileCount = 4;
|
||||
|
||||
/// <summary>
|
||||
/// STUN测试服务器
|
||||
/// </summary>
|
||||
public string STUN_Server = "stun.stunprotocol.org";
|
||||
|
||||
/// <summary>
|
||||
/// STUN测试服务器
|
||||
/// </summary>
|
||||
public int STUN_Server_Port = 3478;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
"Check update when opened": "打开软件时检查更新",
|
||||
"ProfileCount": "快捷配置数量(重启软件生效)",
|
||||
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",
|
||||
"STUN_ServerPort value illegal. Try again.": "STUN端口数值非法。请重试。",
|
||||
"TUN/TAP driver is not detected. Is it installed now?": "未检测到TUN/TAP驱动,是否现在安装?",
|
||||
|
||||
"Profile": "配置名",
|
||||
|
||||
Reference in New Issue
Block a user