Compare commits

..

19 Commits

Author SHA1 Message Date
ChsBuffer
7a15fa7375 修复 端口被占用文本错误,
修复 停止并退出的逻辑错误
2020-07-19 18:18:57 +08:00
ChsBuffer
e10c994e38 Merge pull request #318 from chsbuffer/dev
多项改进,Bug修复
2020-07-19 14:13:20 +08:00
ChsBuffer
54a263ad06 改进已启动时设置端口的占用检查处理 2020-07-19 03:41:19 +08:00
ChsBuffer
8a56dd4582 清理翻译,调整配置按钮点击逻辑,移除系统位元检查 2020-07-19 02:17:32 +08:00
ChsBuffer
cd891cec33 防火墙类异常处理 2020-07-19 02:17:32 +08:00
ChsBuffer
635a033434 改进端口检查 2020-07-19 02:17:32 +08:00
ChsBuffer
6fd3aa48a5 停止时同时结束加密代理和模式 2020-07-19 02:17:31 +08:00
Amazing_DM
a319833bd5 使用进程模式时网卡DNS将自动替换为1.1.1.1和8.8.8.8,关闭后自动恢复
更新驱动文件1.5.9.3
2020-07-18 14:48:23 +08:00
AmazingDM
70e5d8324e Merge pull request #317 from chsbuffer/dev
更新 Controller类,改善错误输出
2020-07-17 19:29:31 +08:00
ChsBuffer
1cecccb173 尝试杀子进程后进行端口检查 2020-07-17 19:23:12 +08:00
ChsBuffer
281c67aced 更新 Controller类
改善错误输出
2020-07-17 19:18:29 +08:00
Amazing_DM
a779295525 fix a bug 2020-07-17 10:55:41 +08:00
AmazingDM
e665850fc9 Merge pull request #316 from Wangrui-i/master
修复端口被占用的提示没有翻译的问题;软件首次启动提示 增加翻译(翻译为当前系统语言)
2020-07-17 10:15:55 +08:00
橘子皮
2537fdd8fe 修复端口被占用的提示没有翻译的问题;软件首次启动提示 增加翻译(翻译为当前系统语言) 2020-07-17 10:03:31 +08:00
AmazingDM
cc459d3f59 Merge pull request #314 from chsbuffer/master
细节修缮
2020-07-17 00:45:32 +08:00
AmazingDM
7c051413d3 Merge branch 'master' into master 2020-07-17 00:45:19 +08:00
AmazingDM
17165e4623 Merge pull request #315 from Wangrui-i/master
新增端口占用检查 #307
2020-07-17 00:25:01 +08:00
橘子皮
a6fd0764e1 新增端口占用检查 #307 2020-07-17 00:12:25 +08:00
ChsBuffer
d27c7c016c 细节修缮 2020-07-16 20:24:02 +08:00
36 changed files with 748 additions and 742 deletions

View File

@@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using Netch.Utils;
namespace Netch.Controllers
@@ -8,10 +7,8 @@ namespace Netch.Controllers
{
public DNSController()
{
AkaName = "dns Service";
MainFile = "unbound";
ExtFiles = new[] {"unbound-service.conf", "forward-zone.conf"};
InitCheck();
Name = "DNS Service";
MainFile = "unbound.exe";
}
/// <summary>
@@ -20,9 +17,7 @@ namespace Netch.Controllers
/// <returns></returns>
public bool Start()
{
if (!Ready) return false;
Instance = GetProcess("bin\\unbound.exe");
Instance = GetProcess();
Instance.StartInfo.Arguments = "-c unbound-service.conf -v";
Instance.OutputDataReceived += OnOutputDataReceived;
@@ -42,11 +37,6 @@ namespace Netch.Controllers
}
}
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
WriteLog(e);
}
public override void Stop()
{
StopInstance();

View File

@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Text;
using System.Text;
using System.Threading;
using Netch.Models;
using Netch.Utils;
@@ -10,8 +9,10 @@ namespace Netch.Controllers
{
public SSController()
{
MainFile = "Shadowsocks";
InitCheck();
Name = "Shadowsocks";
MainFile = "Shadowsocks.exe";
StartedKeywords("listening at");
StoppedKeywords("Invalid config path","usage","plugin service exit unexpectedly");
}
public override bool Start(Server server, Mode mode)
@@ -45,8 +46,7 @@ namespace Netch.Controllers
return true;
}
if (!Ready) return false;
Instance = GetProcess("bin\\Shadowsocks.exe");
Instance = GetProcess();
Instance.StartInfo.Arguments = $"-s {server.Hostname} -p {server.Port} -b {Global.Settings.LocalAddress} -l {Global.Settings.Socks5LocalPort} -m {server.EncryptMethod} -k \"{server.Password}\" -u";
if (!string.IsNullOrWhiteSpace(server.Plugin) && !string.IsNullOrWhiteSpace(server.PluginOption))
@@ -89,18 +89,5 @@ namespace Netch.Controllers
else
StopInstance();
}
public override void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!WriteLog(e)) return;
if (State == State.Starting)
{
if (Instance.HasExited)
State = State.Stopped;
else if (e.Data.Contains("listening at"))
State = State.Started;
else if (e.Data.Contains("Invalid config path") || e.Data.Contains("usage") || e.Data.Contains("plugin service exit unexpectedly")) State = State.Stopped;
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Threading;
using System.Threading;
using Netch.Models;
using Netch.Utils;
@@ -9,16 +8,15 @@ namespace Netch.Controllers
{
public SSRController()
{
MainFile = "ShadowsocksR";
InitCheck();
Name = "ShadowsocksR";
MainFile = "ShadowsocksR.exe";
StartedKeywords("listening at");
StoppedKeywords("Invalid config path","usage");
}
public override bool Start(Server server, Mode mode)
{
if (!Ready) return false;
Instance = GetProcess("bin\\ShadowsocksR.exe");
Instance.StartInfo.FileName = "bin\\ShadowsocksR.exe";
Instance = GetProcess();
Instance.OutputDataReceived += OnOutputDataReceived;
Instance.ErrorDataReceived += OnOutputDataReceived;
@@ -67,19 +65,6 @@ namespace Netch.Controllers
return false;
}
public override void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!WriteLog(e)) return;
if (State == State.Starting)
{
if (Instance.HasExited)
State = State.Stopped;
else if (e.Data.Contains("listening at"))
State = State.Started;
else if (e.Data.Contains("Invalid config path") || e.Data.Contains("usage")) State = State.Stopped;
}
}
public override void Stop()
{
StopInstance();

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Netch.Models;
@@ -12,13 +11,14 @@ namespace Netch.Controllers
{
public TrojanController()
{
MainFile = "Trojan";
InitCheck();
Name = "Trojan";
MainFile = "Trojan.exe";
StartedKeywords("started");
StoppedKeywords("exiting");
}
public override bool Start(Server server, Mode mode)
{
if (!Ready) return false;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new Trojan
{
@@ -32,7 +32,7 @@ namespace Netch.Controllers
}
}));
Instance = GetProcess("bin\\Trojan.exe");
Instance = GetProcess();
Instance.StartInfo.Arguments = "-c ..\\data\\last.json";
Instance.OutputDataReceived += OnOutputDataReceived;
Instance.ErrorDataReceived += OnOutputDataReceived;
@@ -61,19 +61,6 @@ namespace Netch.Controllers
return false;
}
public override void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!WriteLog(e)) return;
if (State == State.Starting)
{
if (Instance.HasExited)
State = State.Stopped;
else if (e.Data.Contains("started"))
State = State.Started;
else if (e.Data.Contains("exiting")) State = State.Stopped;
}
}
public override void Stop()
{
StopInstance();

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Netch.Models;
@@ -13,13 +12,14 @@ namespace Netch.Controllers
{
public VMessController()
{
MainFile = "v2ray";
InitCheck();
Name = "V2Ray";
MainFile = "v2ray.exe";
StartedKeywords("started");
StoppedKeywords("config file not readable", "failed to");
}
public override bool Start(Server server, Mode mode)
{
if (!Ready) return false;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new VMess.Config
{
inbounds = new List<VMess.Inbounds>
@@ -58,14 +58,14 @@ namespace Netch.Controllers
streamSettings = new VMess.StreamSettings
{
network = server.TransferProtocol,
security = server.TLSSecure ? "tls" : "",
security = server.TLSSecure ? "tls" : string.Empty,
wsSettings = server.TransferProtocol == "ws"
? new VMess.WebSocketSettings
{
path = server.Path == "" ? "/" : server.Path,
path = server.Path == string.Empty ? "/" : server.Path,
headers = new VMess.WSHeaders
{
Host = server.Host == "" ? server.Hostname : server.Host
Host = server.Host == string.Empty ? server.Hostname : server.Host
}
}
: null,
@@ -77,10 +77,10 @@ namespace Netch.Controllers
type = server.FakeType,
request = new VMess.TCPRequest
{
path = server.Path == "" ? "/" : server.Path,
path = server.Path == string.Empty ? "/" : server.Path,
headers = new VMess.TCPRequestHeaders
{
Host = server.Host == "" ? server.Hostname : server.Host
Host = server.Host == string.Empty ? server.Hostname : server.Host
}
}
}
@@ -168,7 +168,7 @@ namespace Netch.Controllers
}
}));
Instance = GetProcess("bin\\v2ray.exe");
Instance = GetProcess();
Instance.StartInfo.Arguments = "-config ..\\data\\last.json";
Instance.OutputDataReceived += OnOutputDataReceived;
@@ -203,19 +203,6 @@ namespace Netch.Controllers
return false;
}
public override void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!WriteLog(e)) return;
if (State == State.Starting)
{
if (Instance.HasExited)
State = State.Stopped;
else if (e.Data.Contains("started"))
State = State.Started;
else if (e.Data.Contains("config file not readable") || e.Data.Contains("failed to")) State = State.Stopped;
}
}
public override void Stop()
{
StopInstance();

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Netch.Models;
@@ -10,15 +11,8 @@ namespace Netch.Controllers
{
/// <summary>
/// 控制器名
/// <param />
/// 未赋值会在 <see cref="InitCheck" /> 赋值为 <see cref="MainFile" />
/// </summary>
public string AkaName;
/// <summary>
/// 其他需要文件
/// </summary>
protected string[] ExtFiles;
public string Name;
/// <summary>
/// 进程实例
@@ -30,10 +24,29 @@ namespace Netch.Controllers
/// </summary>
public string MainFile;
/// <summary>
/// 运行检查, 由 <see cref="InitCheck()" /> 赋值
/// </summary>
public bool Ready;
private List<string> _startedKeywords = new List<string>();
private List<string> _stoppedKeywords = new List<string>();
protected bool RedirectStd = true;
protected void StartedKeywords(params string[] texts)
{
foreach (var text in texts)
{
_startedKeywords.Add(text);
}
}
protected void StoppedKeywords(params string[] texts)
{
foreach (var text in texts)
{
_stoppedKeywords.Add(text);
}
}
/// <summary>
/// 当前状态
@@ -55,96 +68,102 @@ namespace Netch.Controllers
}
catch (Exception e)
{
Logging.Error($"停止 {MainFile}.exe 错误:\n" + e);
Logging.Error($"停止 {MainFile} 错误:\n" + e);
}
}
/// <summary>
/// 杀残留进程,清除日志,检查文件
/// </summary>
/// <returns></returns>
protected void InitCheck()
public void ClearLog()
{
if (string.IsNullOrEmpty(AkaName)) AkaName = MainFile;
var result = false;
// 杀残留
MainController.KillProcessByName(MainFile);
// 清日志
try
{
if (File.Exists($"logging\\{AkaName}.log")) File.Delete($"logging\\{AkaName}.log");
if (File.Exists($"logging\\{Name}.log")) File.Delete($"logging\\{Name}.log");
}
catch (Exception)
{
// ignored
}
// 检查文件
var mainResult = true;
var extResult = true;
if (!string.IsNullOrEmpty(MainFile) && !File.Exists($"bin\\{MainFile}.exe"))
{
mainResult = false;
Logging.Error($"主程序 bin\\{MainFile}.exe 不存在");
}
if (ExtFiles == null)
extResult = true;
else
foreach (var f in ExtFiles)
if (!File.Exists($"bin\\{f}"))
{
extResult = false;
Logging.Error($"附加文件 bin\\{f} 不存在");
}
result = extResult && mainResult;
if (!result)
Logging.Error(AkaName + " 未就绪");
Ready = result;
}
/// <summary>
/// 写日志
/// </summary>
/// <param name="std"></param>
/// <returns><see cref="std" />是否为空</returns>
protected bool WriteLog(DataReceivedEventArgs std)
/// <param name="s"></param>
/// <returns><see cref="s" />是否为空</returns>
protected bool Write(string s)
{
if (string.IsNullOrWhiteSpace(std.Data)) return false;
if (string.IsNullOrWhiteSpace(s)) return false;
try
{
File.AppendAllText($"logging\\{AkaName}.log", $@"{std.Data}{Global.EOF}");
File.AppendAllText($"logging\\{Name}.log", s + Global.EOF);
}
catch (Exception e)
{
Logging.Error($"写入{AkaName}日志错误:\n" + e);
Logging.Error($"写入{Name}日志错误:\n" + e);
}
return true;
}
public static Process GetProcess(string path = null, bool redirectStd = true)
public Process GetProcess()
{
var p = new Process
{
StartInfo =
{
Arguments = "",
FileName = Path.GetFullPath($"bin\\{MainFile}"),
WorkingDirectory = $"{Global.NetchDir}\\bin",
CreateNoWindow = true,
RedirectStandardError = redirectStd,
RedirectStandardInput = redirectStd,
RedirectStandardOutput = redirectStd,
RedirectStandardError = RedirectStd,
RedirectStandardInput = RedirectStd,
RedirectStandardOutput = RedirectStd,
UseShellExecute = false
},
EnableRaisingEvents = true
};
if (path != null) p.StartInfo.FileName = Path.GetFullPath(path);
return p;
}
/// <summary>
/// 接收输出数据
/// </summary>
/// <param name="sender">发送者</param>
/// <param name="e">数据</param>
protected void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
// 写入日志
if (!Write(e.Data)) return;
// 检查启动
if (State == State.Starting)
{
if (Instance.HasExited)
{
State = State.Stopped;
return;
}
foreach (var s in _startedKeywords)
{
if (e.Data.Contains(s))
{
State = State.Started;
return;
}
}
foreach (var s in _stoppedKeywords)
{
if (e.Data.Contains(s))
{
State = State.Stopped;
return;
}
}
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Diagnostics;
using Netch.Models;
using Netch.Models;
namespace Netch.Controllers
{
@@ -12,7 +11,5 @@ namespace Netch.Controllers
/// <param name="mode">模式</param>
/// <returns>是否启动成功</returns>
public abstract bool Start(Server server, Mode mode);
public abstract void OnOutputDataReceived(object sender, DataReceivedEventArgs e);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
@@ -11,6 +12,12 @@ namespace Netch.Controllers
{
public class MainController
{
/// <summary>
/// 记录当前使用的端口
/// <see cref="MainForm.LocalPortText"/>
/// </summary>
public static readonly List<int> UsingPorts = new List<int>();
public EncryptedProxy pEncryptedProxyController;
public ModeController pModeController;
@@ -18,7 +25,7 @@ namespace Netch.Controllers
/// <summary>
/// NTT 控制器
/// </summary>
public NTTController pNTTController;
public NTTController pNTTController = new NTTController();
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();
@@ -31,7 +38,6 @@ namespace Netch.Controllers
/// <returns>是否启动成功</returns>
public bool Start(Server server, Mode mode)
{
pNTTController ??= new NTTController();
FlushDNSResolverCache();
var result = false;
@@ -57,13 +63,34 @@ namespace Netch.Controllers
break;
}
MainForm.Instance.StatusText(i18N.Translate("Starting ", pEncryptedProxyController.AkaName));
if (pEncryptedProxyController.Ready) result = pEncryptedProxyController.Start(server, mode);
KillProcessByName(pEncryptedProxyController.MainFile);
// 检查端口是否被占用
if (PortHelper.PortInUse(Global.Settings.Socks5LocalPort))
{
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", "Socks5"));
return false;
}
if (PortHelper.PortInUse(Global.Settings.HTTPLocalPort))
{
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", "HTTP"));
return false;
}
if (PortHelper.PortInUse(Global.Settings.RedirectorTCPPort, PortType.TCP))
{
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", "Redirector TCP"));
return false;
}
Global.MainForm.StatusText(i18N.Translate("Starting ", pEncryptedProxyController.Name));
result = pEncryptedProxyController.Start(server, mode);
}
if (result)
{
// 加密代理已启动
Logging.Info("加密代理已启动");
switch (mode.Type)
{
case 0: // 进程代理模式
@@ -82,28 +109,30 @@ namespace Netch.Controllers
break;
}
if (pModeController != null && pModeController.Ready)
if (pModeController != null)
{
MainForm.Instance.StatusText(i18N.Translate("Starting ", pModeController.AkaName));
Global.MainForm.StatusText(i18N.Translate("Starting ", pModeController.Name));
result = pModeController.Start(server, mode);
}
switch (mode.Type)
if (result)
{
case 0:
case 1:
case 2:
if (result)
switch (mode.Type)
{
case 0:
case 1:
case 2:
Task.Run(() =>
{
MainForm.Instance.NatTypeStatusText(i18N.Translate("Starting NatTester"));
Global.MainForm.NatTypeStatusText(i18N.Translate("Starting NatTester"));
// Thread.Sleep(1000);
var (nttResult, natType, localEnd, publicEnd) = pNTTController.Start();
var country = Utils.Utils.GetCityCode(publicEnd);
if (nttResult) MainForm.Instance.NatTypeStatusText(natType, country);
if (nttResult) Global.MainForm.NatTypeStatusText(natType, country);
});
break;
break;
}
}
}
@@ -117,7 +146,8 @@ namespace Netch.Controllers
/// </summary>
public void Stop()
{
pEncryptedProxyController?.Stop();
Task.Run(() => pEncryptedProxyController?.Stop());
Task.Run(() => UsingPorts.Clear());
pModeController?.Stop();
}

View File

@@ -19,8 +19,7 @@ namespace Netch.Controllers
public HTTPController()
{
AkaName = "HTTP";
Ready = true;
Name = "HTTP";
}
/// <summary>
@@ -31,8 +30,6 @@ namespace Netch.Controllers
/// <returns>是否启动成功</returns>
public override bool Start(Server server, Mode mode)
{
if (!Ready) return false;
RecordPrevious();
try
{

View File

@@ -3,8 +3,6 @@ using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using Netch.Forms;
using Netch.Models;
using Netch.Utils;
using nfapinet;
@@ -15,19 +13,13 @@ namespace Netch.Controllers
{
private static readonly ServiceController NFService = new ServiceController("netfilter2");
private static readonly string BinDriver = "";
private static readonly string BinDriver = string.Empty;
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
public static string DriverVersion(string file)
{
return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : "";
}
private static string[] _sysDns = { };
static NFController()
{
// 生成系统版本
var winNTver = $"{Environment.OSVersion.Version.Major.ToString()}.{Environment.OSVersion.Version.Minor.ToString()}";
switch (winNTver)
switch ($"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor}")
{
case "10.0":
BinDriver = "Win-10.sys";
@@ -41,7 +33,7 @@ namespace Netch.Controllers
BinDriver = "Win-7.sys";
break;
default:
Logging.Error($"不支持的系统版本:{winNTver}");
Logging.Error($"不支持的系统版本:{Environment.OSVersion.Version}");
return;
}
@@ -50,22 +42,24 @@ namespace Netch.Controllers
public NFController()
{
MainFile = "Redirector";
ExtFiles = new[] {Path.GetFileName(BinDriver)};
InitCheck();
if (!File.Exists(SystemDriver))
{
InstallDriver();
}
Name = "Redirector";
MainFile = "Redirector.exe";
StartedKeywords("Started");
StoppedKeywords("Failed", "Unable");
}
public override bool Start(Server server, Mode mode)
{
if (!CheckDriverReady())
Logging.Info("内置驱动版本: " + DriverVersion(BinDriver));
if (DriverVersion(SystemDriver) != DriverVersion(BinDriver))
{
if (File.Exists(SystemDriver))
{
Logging.Info("系统驱动版本: " + DriverVersion(SystemDriver));
Logging.Info("更新驱动");
UninstallDriver();
}
if (!InstallDriver())
return false;
}
@@ -75,7 +69,7 @@ namespace Netch.Controllers
processList += proc + ",";
processList += "NTT.exe";
Instance = GetProcess("bin\\Redirector.exe");
Instance = GetProcess();
if (server.Type != "Socks5")
{
Instance.StartInfo.Arguments += $"-r 127.0.0.1:{Global.Settings.Socks5LocalPort} -p \"{processList}\"";
@@ -109,10 +103,19 @@ namespace Netch.Controllers
{
Thread.Sleep(250);
if (State == State.Started) return true;
if (State == State.Started)
{
//备份并替换系统DNS
_sysDns = DNS.getSystemDns();
string[] dns = {"1.1.1.1", "8.8.8.8"};
DNS.SetDNS(dns);
return true;
}
}
Logging.Error("NF 进程启动超时");
Logging.Error(Name + " 启动超时");
Stop();
if (!RestartService()) return false;
}
@@ -131,11 +134,11 @@ namespace Netch.Controllers
// 防止其他程序占用 重置 NF 百万连接数限制
NFService.Stop();
NFService.WaitForStatus(ServiceControllerStatus.Stopped);
MainForm.Instance.StatusText(i18N.Translate("Starting netfilter2 Service"));
Global.MainForm.StatusText(i18N.Translate("Starting netfilter2 Service"));
NFService.Start();
break;
case ServiceControllerStatus.Stopped:
MainForm.Instance.StatusText(i18N.Translate("Starting netfilter2 Service"));
Global.MainForm.StatusText(i18N.Translate("Starting netfilter2 Service"));
NFService.Start();
break;
}
@@ -157,17 +160,19 @@ namespace Netch.Controllers
return true;
}
private bool CheckDriverReady()
public static string DriverVersion(string file)
{
// 检查驱动是否存在
if (!File.Exists(SystemDriver)) return false;
// 检查驱动版本号
return DriverVersion(SystemDriver) == DriverVersion(BinDriver);
return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
}
/// <summary>
/// 卸载 NF 驱动
/// </summary>
/// <returns>是否成功卸载</returns>
public static bool UninstallDriver()
{
Global.MainForm.StatusText("Uninstall netfilter2");
Logging.Info("卸载NF驱动");
try
{
if (NFService.Status == ServiceControllerStatus.Running)
@@ -182,22 +187,28 @@ namespace Netch.Controllers
}
if (!File.Exists(SystemDriver)) return true;
try
{
NFAPI.nf_unRegisterDriver("netfilter2");
File.Delete(SystemDriver);
return true;
}
catch (Exception ex)
catch (Exception e)
{
throw ex;
Logging.Error(e.ToString());
return false;
}
File.Delete(SystemDriver);
return true;
}
/// <summary>
/// 安装 NF 驱动
/// </summary>
/// <returns>驱动是否安装成功</returns>
public static bool InstallDriver()
{
Logging.Info("安装驱动");
Logging.Info("安装NF驱动");
try
{
File.Copy(BinDriver, SystemDriver);
@@ -208,12 +219,12 @@ namespace Netch.Controllers
return false;
}
MainForm.Instance.StatusText(i18N.Translate("Register driver"));
Global.MainForm.StatusText(i18N.Translate("Register driver"));
// 注册驱动文件
var result = NFAPI.nf_registerDriver("netfilter2");
if (result == NF_STATUS.NF_STATUS_SUCCESS)
{
Logging.Info($"驱动安装成功,当前驱动版本:{DriverVersion(DriverVersion(SystemDriver))}");
Logging.Info($"驱动安装成功,当前驱动版本:{DriverVersion(SystemDriver)}");
}
else
{
@@ -224,38 +235,40 @@ namespace Netch.Controllers
return true;
}
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!WriteLog(e)) return;
if (State == State.Starting)
{
if (Instance.HasExited)
State = State.Stopped;
else if (e.Data.Contains("Started"))
State = State.Started;
else if (e.Data.Contains("Failed") || e.Data.Contains("Unable")) State = State.Stopped;
}
else if (State == State.Started)
{
if (e.Data.StartsWith("[APP][Bandwidth]"))
{
var splited = e.Data.Replace("[APP][Bandwidth]", "").Trim().Split(',');
if (splited.Length == 2)
{
var uploadSplited = splited[0].Split(':');
var downloadSplited = splited[1].Split(':');
if (uploadSplited.Length == 2 && downloadSplited.Length == 2)
if (long.TryParse(uploadSplited[1], out var upload) && long.TryParse(downloadSplited[1], out var download))
Task.Run(() => OnBandwidthUpdated(upload, download));
}
}
}
}
// private new void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
// {
// if (!Write(e.Data)) return;
// if (State == State.Starting)
// {
// if (Instance.HasExited)
// State = State.Stopped;
// else if (e.Data.Contains("Started"))
// State = State.Started;
// else if (e.Data.Contains("Failed") || e.Data.Contains("Unable")) State = State.Stopped;
// }
// else if (State == State.Started)
// {
// if (e.Data.StartsWith("[APP][Bandwidth]"))
// {
// var splited = e.Data.Replace("[APP][Bandwidth]", "").Trim().Split(',');
// if (splited.Length == 2)
// {
// var uploadSplited = splited[0].Split(':');
// var downloadSplited = splited[1].Split(':');
//
// if (uploadSplited.Length == 2 && downloadSplited.Length == 2)
// if (long.TryParse(uploadSplited[1], out var upload) && long.TryParse(downloadSplited[1], out var download))
// Task.Run(() => OnBandwidthUpdated(upload, download));
// }
// }
// }
// }
public override void Stop()
{
StopInstance();
//恢复系统DNS
DNS.SetDNS(_sysDns);
}
/// <summary>

View File

@@ -8,7 +8,6 @@ using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Netch.Forms;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
@@ -35,14 +34,16 @@ namespace Netch.Controllers
public TUNTAPController()
{
MainFile = "tun2socks";
InitCheck();
Name = "Tap";
MainFile = "tun2socks.exe";
StartedKeywords("Running");
StoppedKeywords("failed","invalid vconfig file");
}
/// <summary>
/// 配置 TUNTAP 适配器
/// </summary>
public bool Configure()
private bool Configure()
{
// 查询服务器 IP 地址
var destination = Dns.GetHostAddressesAsync(_savedServer.Hostname);
@@ -60,9 +61,9 @@ namespace Netch.Controllers
/// <summary>
/// 设置绕行规则
/// </summary>
public bool SetupBypass()
private bool SetupBypass()
{
MainForm.Instance.StatusText(i18N.Translate("SetupBypass"));
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
Logging.Info("设置绕行规则 → 设置让服务器 IP 走直连");
// 让服务器 IP 走直连
foreach (var address in _serverAddresses)
@@ -178,7 +179,7 @@ namespace Netch.Controllers
Logging.Info("设置绕行规则 → 处理自定义 DNS 代理");
if (Global.Settings.TUNTAP.UseCustomDNS)
{
var dns = "";
var dns = string.Empty;
foreach (var value in Global.Settings.TUNTAP.DNS)
{
dns += value;
@@ -252,7 +253,7 @@ namespace Netch.Controllers
{
if (Global.Settings.TUNTAP.UseCustomDNS)
{
var dns = "";
var dns = string.Empty;
foreach (var value in Global.Settings.TUNTAP.DNS)
{
dns += value;
@@ -308,9 +309,7 @@ namespace Netch.Controllers
public override bool Start(Server server, Mode mode)
{
if (!Ready) return false;
MainForm.Instance.StatusText(i18N.Translate("Starting Tap"));
Global.MainForm.StatusText(i18N.Translate("Starting Tap"));
_savedMode = mode;
_savedServer = server;
@@ -321,7 +320,7 @@ namespace Netch.Controllers
SetupBypass();
Logging.Info("设置绕行规则完毕");
Instance = GetProcess("bin\\tun2socks.exe");
Instance = GetProcess();
var adapterName = TUNTAP.GetName(Global.TUNTAP.ComponentID);
Logging.Info($"tun2sock使用适配器{adapterName}");
@@ -331,7 +330,7 @@ namespace Netch.Controllers
//if (Global.Settings.TUNTAP.UseCustomDNS || server.Type.Equals("VMess"))
if (Global.Settings.TUNTAP.UseCustomDNS)
{
dns = "";
dns = string.Empty;
foreach (var value in Global.Settings.TUNTAP.DNS)
{
dns += value;
@@ -389,17 +388,6 @@ namespace Netch.Controllers
pDNSController.Stop();
}
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!WriteLog(e)) return;
if (State == State.Starting)
{
if (e.Data.Contains("Running"))
State = State.Started;
else if (e.Data.Contains("failed") || e.Data.Contains("invalid vconfig file")) State = State.Stopped;
}
}
/// <summary>
/// 搜索出口
/// </summary>
@@ -431,7 +419,7 @@ namespace Netch.Controllers
// 通过索引查找对应适配器的 IPv4 地址
if (p.Index == Global.Adapter.Index)
{
var AdapterIPs = "";
var AdapterIPs = string.Empty;
foreach (var ip in adapterProperties.UnicastAddresses)
{

View File

@@ -11,8 +11,8 @@ namespace Netch.Controllers
public NTTController()
{
MainFile = "NTT";
InitCheck();
Name = "NTT";
MainFile = "NTT.exe";
}
/// <summary>
@@ -21,10 +21,9 @@ namespace Netch.Controllers
/// <returns></returns>
public (bool, string, string, string) Start()
{
if (!Ready) return (false, null, null, null);
try
{
Instance = GetProcess("bin\\NTT.exe");
Instance = GetProcess();
Instance.StartInfo.Arguments = $" {Global.Settings.STUN_Server} {Global.Settings.STUN_Server_Port}";
@@ -52,7 +51,7 @@ namespace Netch.Controllers
}
}
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
private new void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
_lastResult = e.Data;

View File

@@ -9,15 +9,13 @@ namespace Netch.Controllers
{
public PrivoxyController()
{
MainFile = "Privoxy";
ExtFiles = new[] {"default.conf"};
InitCheck();
Name = "Privoxy";
MainFile = "Privoxy.exe";
RedirectStd = false;
}
public bool Start(Server server, Mode mode)
{
if (!Ready) return false;
var isSocks5 = server.Type == "Socks5";
var socks5Port = isSocks5 ? server.Port : Global.Settings.Socks5LocalPort;
var text = File.ReadAllText("bin\\default.conf")
@@ -28,7 +26,7 @@ namespace Netch.Controllers
text = text.Replace("/ 127.0.0.1", $"/ {server.Hostname}");
File.WriteAllText("data\\privoxy.conf", text);
Instance = GetProcess("bin\\Privoxy.exe", false);
Instance = GetProcess();
Instance.StartInfo.Arguments = "..\\data\\privoxy.conf";
Instance.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Instance.StartInfo.UseShellExecute = true;

View File

@@ -53,7 +53,7 @@ namespace Netch.Controllers
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
Debug.WriteLine(e.ToString());
if (notifyNoFound) NewVersionFoundFailed?.Invoke(this, new EventArgs());
}
}

View File

@@ -15,9 +15,13 @@ namespace Netch.Forms
partial class MainForm
{
public void ControlFun()
private bool _isFirstCloseWindow = true;
private void ControlFun()
{
SaveConfigs();
//防止模式选择框变成蓝色:D
ModeComboBox.Select(0, 0);
if (State == State.Waiting || State == State.Stopped)
{
// 服务器、模式 需选择
@@ -29,49 +33,34 @@ namespace Netch.Forms
if (ModeComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select an mode first"));
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
return;
}
//MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
UpdateStatus(State.Starting);
Firewall.AddNetchFwRules();
Task.Run(() =>
{
Task.Run(Firewall.AddNetchFwRules);
var server = ServerComboBox.SelectedItem as Models.Server;
var mode = ModeComboBox.SelectedItem as Models.Mode;
MainController ??= new MainController();
var startResult = MainController.Start(server, mode);
if (startResult)
if (_mainController.Start(server, mode))
{
Task.Run(() =>
{
UpdateStatus(State.Started);
StatusText(i18N.Translate(StateExtension.GetStatusString(State)) + PortText(server.Type,mode.Type));
LastUploadBandwidth = 0;
//LastDownloadBandwidth = 0;
//UploadSpeedLabel.Text = "↑: 0 KB/s";
DownloadSpeedLabel.Text = "↑↓: 0 KB/s";
UsedBandwidthLabel.Text = $"{i18N.Translate("Used",": ")}0 KB";
UsedBandwidthLabel.Visible = UploadSpeedLabel.Visible = DownloadSpeedLabel.Visible = true;
UploadSpeedLabel.Visible = false;
Bandwidth.NetTraffic(server, mode, MainController);
UpdateStatus(State.Started,
i18N.Translate(StateExtension.GetStatusString(State.Started)) + LocalPortText(server.Type, mode.Type));
Bandwidth.NetTraffic(server, mode, _mainController);
});
// 如果勾选启动后最小化
if (Global.Settings.MinimizeWhenStarted)
{
WindowState = FormWindowState.Minimized;
NotifyIcon.Visible = true;
if (IsFirstOpened)
if (_isFirstCloseWindow)
{
// 显示提示语
NotifyIcon.ShowBalloonTip(5,
@@ -80,7 +69,7 @@ namespace Netch.Forms
"Netch is now minimized to the notification bar, double click this icon to restore."),
ToolTipIcon.Info);
IsFirstOpened = false;
_isFirstCloseWindow = false;
}
Hide();
@@ -111,8 +100,7 @@ namespace Netch.Forms
}
else
{
UpdateStatus(State.Stopped);
StatusText(i18N.Translate("Start failed"));
UpdateStatus(State.Stopped, i18N.Translate("Start failed"));
}
});
}
@@ -120,57 +108,53 @@ namespace Netch.Forms
{
// 停止
UpdateStatus(State.Stopping);
MainController.Stop();
_mainController.Stop();
UpdateStatus(State.Stopped);
Task.Run(() =>
{
TestServer();
});
Task.Run(TestServer);
}
}
private string PortText(string serverType,int modeType)
private static string LocalPortText(string serverType, int modeType)
{
var text = new StringBuilder(" (");
text.Append(Global.Settings.LocalAddress == "0.0.0.0"
? i18N.Translate("Allow other Devices to connect") + " "
: "");
if (Global.Settings.LocalAddress == "0.0.0.0")
text.Append(i18N.Translate("Allow other Devices to connect") + " ");
if (serverType == "Socks5")
{
// 不可控Socks5
if (modeType == 3 || modeType == 5)
{
// 可控HTTP
text.Append(
$"HTTP {i18N.Translate("Local Port", ": ")}{Global.Settings.HTTPLocalPort}");
MainController.UsingPorts.Add(Global.Settings.HTTPLocalPort);
text.Append($"HTTP {i18N.Translate("Local Port", ": ")}{Global.Settings.HTTPLocalPort}");
}
else
{
// 不可控HTTP
text.Clear();
return string.Empty;
}
}
else
{
// 可控Socks5
text.Append(
$"Socks5 {i18N.Translate("Local Port", ": ")}{Global.Settings.Socks5LocalPort}");
MainController.UsingPorts.Add(Global.Settings.Socks5LocalPort);
text.Append($"Socks5 {i18N.Translate("Local Port", ": ")}{Global.Settings.Socks5LocalPort}");
if (modeType == 3 || modeType == 5)
{
//有HTTP
text.Append(
$" | HTTP {i18N.Translate("Local Port", ": ")}{Global.Settings.HTTPLocalPort}");
// 有HTTP
MainController.UsingPorts.Add(Global.Settings.HTTPLocalPort);
text.Append($" | HTTP {i18N.Translate("Local Port", ": ")}{Global.Settings.HTTPLocalPort}");
}
}
if (text.Length > 0)
{
text.Append(")");
}
if (modeType == 0)
MainController.UsingPorts.Add(Global.Settings.RedirectorTCPPort);
text.Append(")");
return text.ToString();
}
public void OnBandwidthUpdated(long download)
{
try
@@ -198,7 +182,7 @@ namespace Netch.Forms
}
UsedBandwidthLabel.Text =
$"{i18N.Translate("Used",": ")}{Bandwidth.Compute(upload + download)}";
$"{i18N.Translate("Used", ": ")}{Bandwidth.Compute(upload + download)}";
UploadSpeedLabel.Text = $"↑: {Bandwidth.Compute(upload - LastUploadBandwidth)}/s";
DownloadSpeedLabel.Text = $"↓: {Bandwidth.Compute(download - LastDownloadBandwidth)}/s";

View File

@@ -1,5 +1,4 @@
using System;
using System.Data;
using System.Linq;
using System.Net;
using System.ServiceProcess;
@@ -134,8 +133,8 @@ namespace Netch.Forms
Remark = "ProxyUpdate",
Type = 5
};
MainController = new MainController();
MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
_mainController = new MainController();
_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
}
foreach (var item in Global.Settings.SubscribeLink)
@@ -165,8 +164,8 @@ namespace Netch.Forms
}
catch (Exception)
{
// ignored
}
// ignored
}
Global.Settings.Server = Global.Settings.Server.Where(server => server.Group != item.Remark).ToList();
var result = ShareLink.Parse(response);
@@ -203,7 +202,7 @@ namespace Netch.Forms
{
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
ControlButton.Text = i18N.Translate("Start");
MainController.Stop();
_mainController.Stop();
NatTypeStatusLabel.Text = "";
}
@@ -213,7 +212,6 @@ namespace Netch.Forms
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
UpdateStatus(bak_State);
StatusLabel.Text = bak_StateText;
}).ContinueWith(task => { BeginInvoke(new Action(() => { UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = true; })); });
NotifyIcon.ShowBalloonTip(5,
@@ -232,39 +230,6 @@ namespace Netch.Forms
#region
private void RestartServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
StatusText(i18N.Translate("Restarting service"));
Task.Run(() =>
{
try
{
var service = new ServiceController("netfilter2");
if (service.Status == ServiceControllerStatus.Stopped)
{
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running);
}
else if (service.Status == ServiceControllerStatus.Running)
{
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running);
}
}
catch (Exception)
{
NFAPI.nf_registerDriver("netfilter2");
}
MessageBoxX.Show(i18N.Translate("Service has been restarted"), owner: this);
Enabled = true;
});
}
private void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
@@ -281,7 +246,7 @@ namespace Netch.Forms
}
catch (Exception e)
{
MessageBox.Show(i18N.Translate("Error", e.Message));
MessageBoxX.Show(e.ToString(),info:false);
Console.WriteLine(e);
throw;
}
@@ -380,8 +345,8 @@ namespace Netch.Forms
Remark = "ProxyUpdate",
Type = 5
};
MainController = new MainController();
MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
_mainController = new MainController();
_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
using var client = new WebClient();
@@ -403,7 +368,7 @@ namespace Netch.Forms
finally
{
UpdateStatus(State.Waiting);
MainController.Stop();
_mainController.Stop();
}
});
}

View File

@@ -12,19 +12,18 @@ namespace Netch.Forms
public partial class Dummy { }
partial class MainForm
{
/// init at <see cref="MainForm_Load"/>
private int _sizeHeight;
private int _controlHeight;
private int _profileBoxHeight;
private int _profileConfigurationHeight;
private int _profileGroupboxHeight;
private int _configurationGroupBoxHeight;
private void InitProfile()
{
// Clear
foreach (var button in ProfileButtons)
{
button.Dispose();
}
ProfileButtons.Clear();
ProfileTable.ColumnStyles.Clear();
@@ -33,51 +32,51 @@ namespace Netch.Forms
var numProfile = Global.Settings.ProfileCount;
if (numProfile == 0)
{
// Hide Profile GroupBox, Change window size
configLayoutPanel.RowStyles[2].SizeType = SizeType.Percent;
configLayoutPanel.RowStyles[2].Height = 0;
ProfileGroupBox.Visible = false;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight - _controlHeight);
Size = new Size(Size.Width, _sizeHeight - (_controlHeight + _profileBoxHeight));
return;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight - _profileConfigurationHeight);
Size = new Size(Size.Width, _sizeHeight - (_profileConfigurationHeight + _profileGroupboxHeight));
}
configLayoutPanel.RowStyles[2].SizeType = SizeType.AutoSize;
ProfileGroupBox.Visible = true;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight);
Size = new Size(Size.Width, _sizeHeight);
ProfileTable.ColumnCount = numProfile;
while (Global.Settings.Profiles.Count < numProfile)
else
{
Global.Settings.Profiles.Add(new Profile());
}
// Load Profiles
ProfileTable.ColumnCount = numProfile;
// buttons
for (var i = 0; i < numProfile; ++i)
{
var b = new Button();
ProfileTable.Controls.Add(b, i, 0);
b.Location = new Point(i * 100, 0);
b.Click += ProfileButton_Click;
b.Dock = DockStyle.Fill;
b.Text = !Global.Settings.Profiles[i].IsDummy ? Global.Settings.Profiles[i].ProfileName : i18N.Translate("None");
while (Global.Settings.Profiles.Count < numProfile)
{
Global.Settings.Profiles.Add(new Profile());
}
ProfileButtons.Add(b);
}
for (var i = 0; i < numProfile; ++i)
{
var b = new Button();
b.Click += ProfileButton_Click;
b.Dock = DockStyle.Fill;
b.Text = !Global.Settings.Profiles[i].IsDummy ? Global.Settings.Profiles[i].ProfileName : i18N.Translate("None");
// equal column
for (var i = 1; i <= ProfileTable.RowCount; i++)
{
ProfileTable.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
}
ProfileTable.Controls.Add(b, i, 0);
ProfileButtons.Add(b);
}
for (var i = 1; i <= ProfileTable.ColumnCount; i++)
{
ProfileTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
// equal column
for (var i = 1; i <= ProfileTable.RowCount; i++)
{
ProfileTable.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
}
for (var i = 1; i <= ProfileTable.ColumnCount; i++)
{
ProfileTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
}
if (Size.Height == _sizeHeight) return;
configLayoutPanel.RowStyles[2].SizeType = SizeType.AutoSize;
ProfileGroupBox.Visible = true;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight);
Size = new Size(Size.Width, _sizeHeight);
}
}
@@ -129,14 +128,18 @@ namespace Netch.Forms
Global.Settings.Profiles[index] = new Profile(selectedServer, selectedMode, name);
}
public List<Button> ProfileButtons = new List<Button>();
private void RemoveProfile(int index)
{
Global.Settings.Profiles[index] = new Profile();
}
private List<Button> ProfileButtons = new List<Button>();
private void ProfileButton_Click(object sender, EventArgs e)
{
var index = ProfileButtons.IndexOf((Button) sender);
//Utils.Logging.Info(String.Format("Button no.{0} clicked", index));
if (ModifierKeys == Keys.Control)
{
if (ServerComboBox.SelectedIndex == -1)
@@ -145,7 +148,7 @@ namespace Netch.Forms
}
else if (ModeComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select an mode first"));
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
}
else if (ProfileNameText.Text == "")
{
@@ -156,51 +159,53 @@ namespace Netch.Forms
SaveProfile(index);
ProfileButtons[index].Text = ProfileNameText.Text;
}
return;
}
else
if (Global.Settings.Profiles[index].IsDummy)
{
if (ProfileButtons[index].Text == i18N.Translate("Error") || ProfileButtons[index].Text == i18N.Translate("None"))
{
MessageBoxX.Show(i18N.Translate("No saved profile here. Save a profile first by Ctrl+Click on the button"));
}
MessageBoxX.Show(i18N.Translate("No saved profile here. Save a profile first by Ctrl+Click on the button"));
return;
}
try
{
ProfileNameText.Text = LoadProfile(index);
if (ModifierKeys == Keys.Shift)
{
if (MessageBoxX.Show(i18N.Translate("Remove this Profile?"), confirm: true) != DialogResult.OK) return;
RemoveProfile(index);
ProfileButtons[index].Text = i18N.Translate("None");
MessageBoxX.Show(i18N.Translate("Profile Removed!"));
return;
}
// start the profile
var need2ndStart = true;
if (State == State.Waiting || State == State.Stopped)
{
need2ndStart = false;
}
try
{
ProfileNameText.Text = LoadProfile(index);
ControlButton.PerformClick();
if (need2ndStart)
{
Task.Run(() =>
{
while (State != State.Stopped)
{
Thread.Sleep(200);
}
ControlButton.PerformClick();
});
}
}
catch (Exception ee)
// start the profile
ControlFun();
if (State == State.Stopping || State == State.Stopped)
{
Task.Run(() =>
{
Logging.Info(ee.Message);
ProfileButtons[index].Text = i18N.Translate("Error");
Thread.Sleep(1200);
ProfileButtons[index].Text = i18N.Translate("None");
while (State != State.Stopped)
{
Thread.Sleep(250);
}
ControlFun();
});
}
}
catch (Exception ee)
{
Task.Run(() =>
{
Logging.Info(ee.ToString());
ProfileButtons[index].Text = i18N.Translate("Error");
Thread.Sleep(1200);
ProfileButtons[index].Text = i18N.Translate("None");
});
}
}
}
}

View File

@@ -15,7 +15,7 @@ namespace Netch.Forms
{
#region Server
public void TestServer()
private static void TestServer()
{
try
{
@@ -24,6 +24,7 @@ namespace Netch.Forms
}
catch (Exception)
{
// ignored
}
}
@@ -51,7 +52,7 @@ namespace Netch.Forms
#region Mode
public void InitMode()
private void InitMode()
{
ModeComboBox.Items.Clear();
Global.ModeFiles.Clear();
@@ -139,7 +140,7 @@ namespace Netch.Forms
}
}
public void SelectLastMode()
private void SelectLastMode()
{
// 如果值合法,选中该位置
if (Global.Settings.ModeComboBoxSelectedIndex > 0 &&
@@ -182,7 +183,7 @@ namespace Netch.Forms
#endregion
/// <summary>
/// Init at MainForm_Load()
/// Init at <see cref="MainForm_Load"/>
/// </summary>
private int _eWidth;
@@ -205,32 +206,18 @@ namespace Netch.Forms
switch (cbx.Items[e.Index])
{
case Models.Server _:
case Models.Server item:
{
var item = cbx.Items[e.Index] as Models.Server;
// 计算延迟底色
SolidBrush brush;
if (item.Delay > 200)
{
// 红色
brush = new SolidBrush(Color.Red);
}
else if (item.Delay > 80)
{
// 黄色
brush = new SolidBrush(Color.Yellow);
}
else if (item.Delay >= 0)
{
// 绿色
brush = new SolidBrush(Color.FromArgb(50, 255, 56));
}
else
{
// 灰色
brush = new SolidBrush(Color.Gray);
}
// 绘制延迟底色
e.Graphics.FillRectangle(brush, _eWidth * 9, e.Bounds.Y, _eWidth, e.Bounds.Height);
@@ -240,10 +227,8 @@ namespace Netch.Forms
_eWidth * 9 + _eWidth / 30, e.Bounds.Y);
break;
}
case Models.Mode _:
case Models.Mode item:
{
var item = cbx.Items[e.Index] as Models.Mode;
// 绘制 模式Box 底色
e.Graphics.FillRectangle(new SolidBrush(Color.Gray), _eWidth * 9, e.Bounds.Y, _eWidth,
e.Bounds.Height);
@@ -257,6 +242,7 @@ namespace Netch.Forms
}
catch (Exception)
{
// ignored
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Netch.Forms
/// </summary>
public State State { get; private set; } = State.Waiting;
public void NatTypeStatusText(string text = "",string Country = "")
public void NatTypeStatusText(string text = "", string country = "")
{
if (State != State.Started)
{
@@ -27,9 +27,9 @@ namespace Netch.Forms
if (!string.IsNullOrEmpty(text))
{
if (Country != "")
if (country != "")
{
NatTypeStatusLabel.Text = String.Format("NAT{0}{1}[{2}]", i18N.Translate(": "), text, Country);
NatTypeStatusLabel.Text = String.Format("NAT{0}{1}[{2}]", i18N.Translate(": "), text, country);
}
else
{
@@ -43,12 +43,16 @@ namespace Netch.Forms
}
else
{
NatTypeStatusLabel.Text = "NAT" + i18N.Translate(": ") + i18N.Translate("Test failed");
NatTypeStatusLabel.Text = $@"NAT{i18N.Translate(": ", "Test failed")}";
}
NatTypeStatusLabel.Visible = true;
}
/// <summary>
/// 更新 NAT指示灯颜色
/// </summary>
/// <param name="natType"></param>
private void UpdateNatTypeLight(STUN_Client.NatType natType)
{
Color c;
@@ -76,19 +80,34 @@ namespace Netch.Forms
}
/// <summary>
/// 更新状态栏文本
/// </summary>
/// <param name="text"></param>
public void StatusText(string text)
{
StatusLabel.Text = i18N.Translate("Status", ": ") + text;
}
/// <summary>
/// Update UI, Status, Status Label
/// 更新 UI, 状态栏文本, 状态
/// </summary>
/// <param name="state"></param>
public void UpdateStatus(State state)
/// <param name="text"></param>
private void UpdateStatus(State state, string text = "")
{
State = state;
StatusText(i18N.Translate(StateExtension.GetStatusString(state)));
StatusText(text == "" ? i18N.Translate(StateExtension.GetStatusString(state)) : text);
void MenuStripsEnabled(bool enabled)
{
// 需要禁用的菜单项
UninstallServiceToolStripMenuItem.Enabled =
updateACLWithProxyToolStripMenuItem.Enabled =
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
reinstallTapDriverToolStripMenuItem.Enabled = enabled;
}
// TODO 补充
switch (state)
{
@@ -96,34 +115,33 @@ namespace Netch.Forms
ControlButton.Enabled = true;
ControlButton.Text = i18N.Translate("Start");
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
updateACLWithProxyToolStripMenuItem.Enabled = true;
NatTypeStatusText();
break;
case State.Starting:
ControlButton.Enabled = false;
ControlButton.Text = "...";
ServerComboBox.Enabled = false;
ModeComboBox.Enabled = false;
ConfigurationGroupBox.Enabled = false;
UninstallServiceToolStripMenuItem.Enabled = false;
updateACLWithProxyToolStripMenuItem.Enabled = false;
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = false;
reinstallTapDriverToolStripMenuItem.Enabled = false;
MenuStripsEnabled(false);
break;
case State.Started:
ControlButton.Enabled = true;
ControlButton.Text = i18N.Translate("Stop");
LastUploadBandwidth = 0;
//LastDownloadBandwidth = 0;
//UploadSpeedLabel.Text = "↑: 0 KB/s";
DownloadSpeedLabel.Text = @"↑↓: 0 KB/s";
UsedBandwidthLabel.Text = $@"{i18N.Translate("Used", ": ")}0 KB";
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = true;
break;
case State.Stopping:
ControlButton.Enabled = false;
ControlButton.Text = "...";
ProfileGroupBox.Enabled = false;
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = SettingsButton.Enabled = true;
UsedBandwidthLabel.Visible = UploadSpeedLabel.Visible = DownloadSpeedLabel.Visible = false;
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = false;
NatTypeStatusText();
break;
case State.Stopped:
@@ -133,14 +151,10 @@ namespace Netch.Forms
LastUploadBandwidth = 0;
LastDownloadBandwidth = 0;
ServerComboBox.Enabled = true;
ModeComboBox.Enabled = true;
ProfileGroupBox.Enabled = true;
ConfigurationGroupBox.Enabled = true;
UninstallServiceToolStripMenuItem.Enabled = true;
updateACLWithProxyToolStripMenuItem.Enabled = true;
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = true;
reinstallTapDriverToolStripMenuItem.Enabled = true;
MenuStripsEnabled(true);
break;
case State.Terminating:
@@ -148,7 +162,10 @@ namespace Netch.Forms
}
}
public void UpdateStatus()
/// <summary>
/// 刷新 UI
/// </summary>
private void UpdateStatus()
{
UpdateStatus(State);
}

View File

@@ -19,18 +19,7 @@ namespace Netch.Forms
/// <summary>
/// 主控制器
/// </summary>
public MainController MainController;
/// <summary>
/// 是否第一次打开
/// </summary>
public bool IsFirstOpened = true;
/// <summary>
/// 主窗体的静态实例
/// </summary>
public static MainForm Instance;
private MainController _mainController = new MainController();
public MainForm()
{
@@ -40,8 +29,6 @@ namespace Netch.Forms
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
CheckForIllegalCrossThreadCalls = false;
// MenuStrip.Renderer = new Override.ToolStripProfessionalRender();
Instance = this;
}
private void SaveConfigs()
@@ -64,6 +51,9 @@ namespace Netch.Forms
private void MainForm_Load(object sender, EventArgs e)
{
// 计算 ComboBox绘制 目标宽度
_eWidth = ServerComboBox.Width / 10;
// 加载服务器
InitServer();
@@ -73,18 +63,16 @@ namespace Netch.Forms
// 加载翻译
InitText();
//
// 隐藏 NatTypeStatusLabel
NatTypeStatusText();
// 加载快速配置
_sizeHeight = Size.Height;
_controlHeight = ConfigurationGroupBox.Controls[0].Height / 3;
_profileBoxHeight = ProfileGroupBox.Height;
_configurationGroupBoxHeight = ConfigurationGroupBox.Height;
_profileConfigurationHeight = ConfigurationGroupBox.Controls[0].Height / 3; // 因为 AutoSize, 所以得到的是Controls的总高度
_profileGroupboxHeight = ProfileGroupBox.Height;
// 加载快速配置
InitProfile();
// 为 ComboBox绘制 收集宽度数据
_eWidth = ServerComboBox.Width / 10;
// 自动检测延迟
Task.Run(() =>
@@ -132,7 +120,7 @@ namespace Netch.Forms
WindowState = FormWindowState.Minimized;
NotifyIcon.Visible = true;
if (IsFirstOpened)
if (_isFirstCloseWindow)
{
// 显示提示语
NotifyIcon.ShowBalloonTip(5,
@@ -140,7 +128,7 @@ namespace Netch.Forms
i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."),
ToolTipIcon.Info);
IsFirstOpened = false;
_isFirstCloseWindow = false;
}
Hide();
@@ -155,8 +143,6 @@ namespace Netch.Forms
private void ControlButton_Click(object sender, EventArgs e)
{
//防止模式选择框变成蓝色:D
ModeComboBox.Select(0, 0);
ControlFun();
}
@@ -184,7 +170,7 @@ namespace Netch.Forms
InitProfile();
}
public void InitText()
private void InitText()
{
ServerToolStripMenuItem.Text = i18N.Translate("Server");
ImportServersFromClipboardToolStripMenuItem.Text = i18N.Translate("Import Servers From Clipboard");
@@ -207,16 +193,16 @@ namespace Netch.Forms
reinstallTapDriverToolStripMenuItem.Text = i18N.Translate("Reinstall TUN/TAP driver");
OpenDirectoryToolStripMenuItem.Text = i18N.Translate("Open Directory");
AboutToolStripButton.Text = i18N.Translate("About");
VersionLabel.Text = i18N.Translate("xxx");
// VersionLabel.Text = i18N.Translate("xxx");
exitToolStripMenuItem.Text = i18N.Translate("Exit");
RelyToolStripMenuItem.Text = i18N.Translate("Unable to start? Click me to download");
ConfigurationGroupBox.Text = i18N.Translate("Configuration");
ProfileLabel.Text = i18N.Translate("Profile");
ModeLabel.Text = i18N.Translate("Mode");
ServerLabel.Text = i18N.Translate("Server");
UsedBandwidthLabel.Text = i18N.Translate("Used: 0 KB");
DownloadSpeedLabel.Text = i18N.Translate("↓: 0 KB/s");
UploadSpeedLabel.Text = i18N.Translate("↑: 0 KB/s");
// UsedBandwidthLabel.Text = i18N.Translate("Used: 0 KB");
// DownloadSpeedLabel.Text = i18N.Translate("↓: 0 KB/s");
// UploadSpeedLabel.Text = i18N.Translate("↑: 0 KB/s");
NotifyIcon.Text = i18N.Translate("Netch");
ShowMainFormToolStripButton.Text = i18N.Translate("Show");
ExitToolStripButton.Text = i18N.Translate("Exit");
@@ -230,6 +216,51 @@ namespace Netch.Forms
VersionLabel.Text = UpdateChecker.Version;
}
private void Exit(bool forceExit = false)
{
if (IsDisposed) return;
// 已启动
if (State != State.Waiting && State != State.Stopped)
{
if (Global.Settings.StopWhenExited || forceExit)
{
UpdateStatus(State.Stopping);
ControlFun();
}
else
{
// 未开启自动停止
MessageBoxX.Show(i18N.Translate("Please press Stop button first"));
Visible = true;
ShowInTaskbar = true; // 显示在系统任务栏
WindowState = FormWindowState.Normal; // 还原窗体
NotifyIcon.Visible = true; // 托盘图标隐藏
return;
}
}
NotifyIcon.Visible = false;
Hide();
Task.Run(() =>
{
for (var i = 0; i < 16; i++)
{
if (State == State.Waiting || State == State.Stopped)
break;
Thread.Sleep(250);
}
SaveConfigs();
UpdateStatus(State.Terminating);
Dispose();
Environment.Exit(Environment.ExitCode);
});
}
#region MISC
/// <summary>
@@ -303,7 +334,6 @@ namespace Netch.Forms
Enabled = true;
StatusText(i18N.Translate("Test done"));
Refresh();
Configuration.Save();
});
}
@@ -326,7 +356,7 @@ namespace Netch.Forms
}
else
{
MessageBoxX.Show(i18N.Translate("Please select an mode first"));
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
}
}
@@ -351,7 +381,7 @@ namespace Netch.Forms
}
else
{
MessageBoxX.Show(i18N.Translate("Please select an mode first"));
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
}
}
@@ -368,6 +398,7 @@ namespace Netch.Forms
}
catch (Exception)
{
// ignored
}
}
else
@@ -414,49 +445,6 @@ namespace Netch.Forms
Activate();
}
private void Exit(bool forceExit = false)
{
// 已启动
if (State != State.Waiting && State != State.Stopped)
{
if (forceExit)
ControlFun();
else
{
if (!Global.Settings.StopWhenExited)
{
// 未开启自动停止
MessageBoxX.Show(i18N.Translate("Please press Stop button first"));
Visible = true;
ShowInTaskbar = true; // 显示在系统任务栏
WindowState = FormWindowState.Normal; // 还原窗体
NotifyIcon.Visible = true; // 托盘图标隐藏
return;
}
}
}
NotifyIcon.Visible = false;
Hide();
Task.Run(() =>
{
for (var i = 0; i < 16; i++)
{
if (State == State.Waiting || State == State.Stopped)
break;
Thread.Sleep(250);
}
SaveConfigs();
UpdateStatus(State.Terminating);
Dispose();
Environment.Exit(Environment.ExitCode);
});
}
private void ExitToolStripButton_Click(object sender, EventArgs e)
{
Exit();

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Net;
using System.Windows.Forms;
using Netch.Models;
using Netch.Utils;
using TaskScheduler;
@@ -33,6 +34,7 @@ namespace Netch.Forms
dns += ip;
dns += ',';
}
dns = dns.Trim();
TUNTAPDNSTextBox.Text = dns.Substring(0, dns.Length - 1);
}
@@ -120,6 +122,7 @@ namespace Netch.Forms
dns += ip;
dns += ',';
}
dns = dns.Trim();
TUNTAPDNSTextBox.Text = dns.Substring(0, dns.Length - 1);
}
@@ -183,7 +186,10 @@ namespace Netch.Forms
folder.GetTask("Netch Startup");
taskIsExists = true;
}
catch (Exception) { }
catch (Exception)
{
// ignored
}
if (RunAtStartup.Checked)
{
@@ -196,7 +202,7 @@ namespace Netch.Forms
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
var action = (IExecAction)task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
var action = (IExecAction) task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
action.Path = Application.ExecutablePath;
@@ -204,7 +210,7 @@ namespace Netch.Forms
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
folder.RegisterTaskDefinition("Netch Startup", task, (int)_TASK_CREATION.TASK_CREATE, null, null, _TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null, _TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
}
else
{
@@ -212,77 +218,15 @@ namespace Netch.Forms
folder.DeleteTask("Netch Startup", 0);
}
try
{
var Socks5Port = int.Parse(Socks5PortTextBox.Text);
if (Socks5Port > 0 && Socks5Port < 65536)
{
Global.Settings.Socks5LocalPort = Socks5Port;
}
else
{
throw new FormatException();
}
}
catch (FormatException)
{
Socks5PortTextBox.Text = Global.Settings.Socks5LocalPort.ToString();
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
// 端口检查
if (!CheckPortText("Socks5", ref Socks5PortTextBox, ref Global.Settings.Socks5LocalPort))
return;
}
try
{
var HTTPPort = int.Parse(HTTPPortTextBox.Text);
if (HTTPPort > 0 && HTTPPort < 65536)
{
Global.Settings.HTTPLocalPort = HTTPPort;
}
else
{
throw new FormatException();
}
}
catch (FormatException)
{
HTTPPortTextBox.Text = Global.Settings.HTTPLocalPort.ToString();
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
if (!CheckPortText("HTTP", ref HTTPPortTextBox, ref Global.Settings.HTTPLocalPort))
return;
}
try
{
var RedirectorPort = int.Parse(RedirectorTextBox.Text);
if (RedirectorPort > 0 && RedirectorPort < 65536)
{
Global.Settings.RedirectorTCPPort = RedirectorPort;
}
else
{
throw new FormatException();
}
}
catch (FormatException)
{
RedirectorTextBox.Text = Global.Settings.RedirectorTCPPort.ToString();
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
if (!CheckPortText("RedirectorTCP", ref RedirectorTextBox, ref Global.Settings.RedirectorTCPPort, PortType.TCP))
return;
}
if (AllowDevicesCheckBox.Checked)
{
Global.Settings.LocalAddress = "0.0.0.0";
}
else
{
Global.Settings.LocalAddress = "127.0.0.1";
}
Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1";
try
{
@@ -310,12 +254,14 @@ namespace Netch.Forms
DNS += ip;
DNS += ',';
}
DNS = DNS.Trim();
TUNTAPDNSTextBox.Text = DNS.Substring(0, DNS.Length - 1);
UseCustomDNSCheckBox.Checked = Global.Settings.TUNTAP.UseCustomDNS;
return;
}
try
{
var ProfileCount = int.Parse(ProfileCount_TextBox.Text);
@@ -336,6 +282,7 @@ namespace Netch.Forms
return;
}
try
{
var STUN_Server = STUN_ServerTextBox.Text;
@@ -359,6 +306,7 @@ namespace Netch.Forms
return;
}
try
{
Global.Settings.StartedTcping = EnableStartedTcping_CheckBox.Checked;
@@ -402,5 +350,43 @@ namespace Netch.Forms
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}
/// <summary>
///
/// </summary>
/// <param name="portName"></param>
/// <param name="portTextBox"></param>
/// <param name="originPort"></param>
/// <param name="portType"></param>
/// <returns></returns>
/// <exception cref="FormatException"></exception>
private bool CheckPortText(string portName, ref TextBox portTextBox, ref int originPort, PortType portType = PortType.Both)
{
// 端口检查
try
{
var port = int.Parse(portTextBox.Text);
if (port <= 0 || port >= 65536)
{
throw new FormatException();
}
if (PortHelper.PortInUse(port, portType))
{
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
return false;
}
originPort = port;
}
catch (FormatException)
{
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
return false;
}
return true;
}
}
}
}

View File

@@ -161,7 +161,7 @@ namespace Netch.Forms
Configuration.Save();
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
MessageBoxX.Show(i18N.Translate("Successfully saved"));
MessageBoxX.Show(i18N.Translate("Saved"));
}
});
if (saveFlag)
@@ -200,7 +200,7 @@ namespace Netch.Forms
{
Configuration.Save();
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
MessageBoxX.Show(i18N.Translate("Successfully saved"));
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}
/// <summary>

View File

@@ -16,7 +16,7 @@ namespace Netch
public static readonly string NetchDir = (AppDomain.CurrentDomain.BaseDirectory).TrimEnd();
/// <summary>
/// 主窗体
/// 主窗体的静态实例
/// </summary>
public static Forms.MainForm MainForm;

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Forms;
using Netch.Utils;
@@ -57,6 +58,8 @@ namespace Netch
// 记录当前系统语言
Logging.Info($"当前语言:{Global.Settings.Language}");
Logging.Info($"版本:{UpdateChecker.Owner}/{UpdateChecker.Repo} {UpdateChecker.Version}");
Logging.Info($"主程序创建日期:{File.GetCreationTime(Global.NetchDir + "\\Netch.exe"):yyyy-M-d HH:mm}");
// 检查是否已经运行
if (!mutex.WaitOne(0, false))
@@ -68,20 +71,6 @@ namespace Netch
Environment.Exit(1);
}
var OS = Environment.Is64BitOperatingSystem ? "x64" : "x86";
var PROC = Environment.Is64BitProcess ? "x64" : "x86";
// 如果系统位数与程序位数不一致
if (OS != PROC)
{
// 弹出提示
MessageBoxX.Show($"{i18N.Translate("Netch is not compatible with your system.")}\n{i18N.Translate("Current arch of Netch:")} {PROC}\n{i18N.Translate("Current arch of system:")} {OS}");
// 退出进程
Environment.Exit(1);
}
// 绑定错误捕获
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += Application_OnException;

View File

@@ -70,6 +70,7 @@
</ItemGroup>
<ItemGroup>
<Reference Include="System.Management" />
<Reference Include="System.Net.Http" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Web" />

View File

@@ -3,10 +3,8 @@
"Information": "信息",
"Error": "错误",
"If this is your first time using this software,\n please check http://netch.org to install supports first,\n or the program may report errors.": "如果你是第一次使用本软件,\n请务必前往http://netch.org安装程序所需依赖\n否则程序将无法正常运行",
"Netch is already running": "Netch 已经在运行中",
"Netch is not compatible with your system.": "Netch 和你的系统不兼容",
"Current arch of Netch:": "当前 Netch 架构:",
"Current arch of system:": "当前系统架构:",
"Start": "启动",
"Stop": "停止",
@@ -17,7 +15,6 @@
"Stopping": "正在停止中",
"Stopped": "已停止",
"Starting ": "正在启动 ",
"v2ray": "V2Ray",
"Starting Tap": "正在启动 TUN/TAP",
"Starting NatTester": "正在启动 NAT 测试",
"Starting LocalDns service": "正在启动本地 DNS 服务",
@@ -40,7 +37,6 @@
"Add [ShadowsocksR] Server": "添加 [ShadowsocksR] 服务器",
"Add [VMess] Server": "添加 [VMess] 服务器",
"Add [Trojan] Server": "添加 [Trojan] 服务器",
"VMess is currently not supported. For more information, please see our Github releases\n\nPress OK will redirect": "当前不支持 VMess 服务器。需要更多信息请查看我们的 Github 发布页\n\n点击 OK 将会跳转",
"Netch is now minimized to the notification bar, double click this icon to restore.": "Netch 已最小化至通知栏,双击此图标恢复窗口。",
"New version available": "发现新版本",
"Mode": "模式",
@@ -78,9 +74,6 @@
"Update servers error from {0}": "从 {0} 更新服务器失败",
"Options": "选项",
"Restart Service": "重启服务",
"Restarting service": "正在重启服务中",
"Service has been restarted": "服务已重启",
"Uninstall Service": "卸载服务",
"Uninstalling Service": "正在卸载服务中",
"Service has been uninstalled": "服务已卸载",
@@ -106,9 +99,11 @@
"Please press Stop button first": "请先点击停止按钮",
"Please select a server first": "请先选择一个服务器",
"Please select an mode first": "请先选择一个模式",
"Please select a mode first": "请先选择一个模式",
"Please enter a profile name first": "请先为该配置设置一个名称",
"No saved profile here. Save a profile first by Ctrl+Click on the button": "当前按钮下没有保存配置,请先使用 CTRL + 左键 点击该按钮保存一个配置",
"Remove this Profile?": "确认删除此配置?",
"Profile Removed!": "配置已删除!",
"Used": "已使用",
"Status": "状态",
@@ -142,7 +137,6 @@
"Remark can not be empty": "备注不可为空",
"Link can not be empty": "链接不可为空",
"Link must start with http:// or https://": "链接必须以 http:// 或 https:// 开头",
"Successfully saved": "保存成功",
"Please fill in alterID": "请填写额外ID",
"Settings": "设置",
@@ -169,7 +163,6 @@
"Detection interval value illegal. Try again.": "检测间隔值非法。请重试。",
"TUN/TAP driver is not detected. Is it installed now?": "未检测到 TUN/TAP 驱动,是否现在安装?",
"Failed to set the system proxy, it may be caused by the lack of dependent programs. Do you want to jump to Netch's official website to download dependent programs?": "设置系统代理失败,可能是缺少依赖导致,是否跳转 Netch 官网下载依赖程序?",
"Experimental function": "实验性功能",
"Delay test after start": "启动后延迟测试",
"Enable": "启用",
"Detection interval(sec)": "检测间隔(秒)",
@@ -177,7 +170,6 @@
"STUN Server Port": "STUN 服务器端口",
"Custom ACL": "自定义 ACL 规则",
"Language": "语言",
"Saved.": "保存成功",
"Profile": "配置名",
"Profiles": "配置",
@@ -187,6 +179,8 @@
"Exit": "退出",
"Unable to start? Click me to download": "无法启动?点我下载依赖",
"The {0} port is in use.": "{0} 端口已被占用",
"Bypass LAN": "[网页代理] 绕过局域网",
"Bypass LAN (Non System Proxy)": "[网页代理] 绕过局域网(不设置系统代理)",
"Bypass LAN (TUN/TAP)": "[TUN/TAP] 绕过局域网",

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
@@ -48,27 +49,27 @@ namespace Netch.Utils
//int sent = 0;
//var processList = Process.GetProcessesByName(ProcessName).Select(p => p.Id).ToHashSet();
var processList = new List<int>();
if (server.Type.Equals("Socks5") && mainController.pModeController.AkaName == "HTTP")
var instances = new List<Process>();
if (server.Type.Equals("Socks5") && mainController.pModeController.Name == "HTTP")
{
processList.Add(((HTTPController) mainController.pModeController).pPrivoxyController.Instance.Id);
instances.Add(((HTTPController) mainController.pModeController).pPrivoxyController.Instance);
}
else if (server.Type.Equals("SS") && Global.Settings.BootShadowsocksFromDLL)
{
processList.Add(Process.GetCurrentProcess().Id);
instances.Add(Process.GetCurrentProcess());
}
else if (mainController.pEncryptedProxyController != null)
{
// mainController.pServerClientController.Instance
processList.Add(mainController.pEncryptedProxyController.Instance.Id);
instances.Add(mainController.pEncryptedProxyController.Instance);
}
else if (mainController.pModeController != null)
{
processList.Add(mainController.pModeController.Instance.Id);
instances.Add(mainController.pModeController.Instance);
}
Logging.Info("启动流量统计 PID" + string.Join(",", processList.ToArray()));
var processList = instances.Select(instance => instance.Id).ToList();
Logging.Info("流量统计进程:" + string.Join(",", instances.Select(instance => $"({instance.Id})"+instance.ProcessName).ToArray()));
Task.Run(() =>
{
@@ -101,18 +102,18 @@ namespace Netch.Utils
}
});
if ((Convert.ToInt32(MainForm.Instance.LastDownloadBandwidth) - Convert.ToInt32(received)) == 0)
if ((Convert.ToInt32(Global.MainForm.LastDownloadBandwidth) - Convert.ToInt32(received)) == 0)
{
MainForm.Instance.OnBandwidthUpdated(0);
Global.MainForm.OnBandwidthUpdated(0);
received = 0;
}
while (MainForm.Instance.State != State.Stopped)
while (Global.MainForm.State != State.Stopped)
{
Task.Delay(1000).Wait();
lock (counterLock)
{
MainForm.Instance.OnBandwidthUpdated(Convert.ToInt64(received));
Global.MainForm.OnBandwidthUpdated(Convert.ToInt64(received));
}
}
}

View File

@@ -69,7 +69,8 @@ namespace Netch.Utils
else
{
// 弹出提示
MessageBoxX.Show("如果你是第一次使用本软件\n请务必前往http://netch.org 安装程序所需依赖,\n否则程序将无法正常运行", i18N.Translate("注意!"));
i18N.Load("System");
MessageBoxX.Show(i18N.Translate("If this is your first time using this software,\n please check http://netch.org to install supports first,\n or the program may report errors."));
// 创建 data 文件夹并保存默认设置
Save();

View File

@@ -1,6 +1,9 @@
using System;
using System.Collections;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
namespace Netch.Utils
{
@@ -45,5 +48,51 @@ namespace Netch.Utils
return null;
}
}
/// <summary>
/// 设置DNS
/// </summary>
/// <param name="dns"></param>
public static void SetDNS(string[] dns)
{
ManagementClass wmi = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = wmi.GetInstances();
ManagementBaseObject inPar = null;
ManagementBaseObject outPar = null;
foreach (ManagementObject mo in moc)
{
//如果没有启用IP设置的网络设备则跳过如果是虚拟机网卡也跳过
if (!(bool)mo["IPEnabled"] ||
mo["Description"].ToString().Contains("Virtual") ||
mo["Description"].ToString().Contains("VMware") ||
mo["Description"].ToString().Contains("TAP"))
continue;
//设置DNS地址
if (dns != null)
{
inPar = mo.GetMethodParameters("SetDNSServerSearchOrder");
inPar["DNSServerSearchOrder"] = dns;
outPar = mo.InvokeMethod("SetDNSServerSearchOrder", inPar, null);
}
}
}
/// <summary>
/// 从网卡获取ip设置信息
/// </summary>
public static string[] getSystemDns()
{
var systemDns = new[] { "223.5.5.5", "1.1.1.1" };
foreach (var network in NetworkInterface.GetAllNetworkInterfaces())
if (!network.Description.Contains("Virtual") &&
!network.Description.Contains("VMware") &&
!network.Description.Contains("TAP") &&
network.OperationalStatus == OperationalStatus.Up &&
network.GetIPProperties()?.GatewayAddresses.Count != 0)
{
systemDns = network.GetIPProperties().DnsAddresses.Select(dns => dns.ToString()).ToArray();
}
return systemDns;
}
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Linq;
using NetFwTypeLib;
namespace Netch.Utils
@@ -37,7 +38,14 @@ namespace Netch.Utils
/// </summary>
public static void RemoveFwRules()
{
RemoveFwRules(NetchAutoRule);
try
{
RemoveFwRules(NetchAutoRule);
}
catch (Exception e)
{
Logging.Warning("添加防火墙规则错误\n" + e);
}
}
/// <summary>
@@ -45,16 +53,23 @@ namespace Netch.Utils
/// </summary>
public static void AddNetchFwRules()
{
if (GetFwRulePath(Netch).StartsWith(Global.NetchDir) && GetFwRulesNumber(Netch) >= ProgramPath.Length) return;
RemoveNetchFwRules();
foreach (var p in ProgramPath)
try
{
var path = Path.GetFullPath(p);
if (File.Exists(path))
if (GetFwRulePath(Netch).StartsWith(Global.NetchDir) && GetFwRulesNumber(Netch) >= ProgramPath.Length) return;
RemoveNetchFwRules();
foreach (var p in ProgramPath)
{
AddFwRule("Netch", path);
var path = Path.GetFullPath(p);
if (File.Exists(path))
{
AddFwRule("Netch", path);
}
}
}
catch (Exception e)
{
Logging.Warning("添加防火墙规则错误(如已关闭防火墙则可无视此错误)\n" + e);
}
}
/// <summary>
@@ -62,7 +77,15 @@ namespace Netch.Utils
/// </summary>
private static void RemoveNetchFwRules()
{
RemoveFwRules(Netch);
try
{
RemoveFwRules(Netch);
}
catch (Exception e)
{
Logging.Warning("清除防火墙规则错误\n" + e);
// ignored
}
}
#region
@@ -76,7 +99,7 @@ namespace Netch.Utils
rule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
// ApplicationName 大小不敏感
rule.ApplicationName = exeFullPath;
// rule.Description = "Used to block all internet access.";
// rule.Description = "";
rule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
rule.Enabled = true;
rule.InterfaceTypes = "All";
@@ -87,17 +110,10 @@ namespace Netch.Utils
private static void RemoveFwRules(string ruleName)
{
try
var c = GetFwRulesNumber(ruleName);
foreach (var _ in new bool[c])
{
var c = GetFwRulesNumber(ruleName);
foreach (var _ in new bool[c])
{
FwPolicy.Rules.Remove(ruleName);
}
}
catch (Exception e)
{
Logging.Info("Netch 自带程序添加防火墙出错(如已关闭防火墙则可无视此错误)\n" + e);
FwPolicy.Rules.Remove(ruleName);
}
}
@@ -111,8 +127,8 @@ namespace Netch.Utils
{
try
{
var rule = (INetFwRule2)FwPolicy.Rules.Item(ruleName);
return rule.ApplicationName;
var rule = (INetFwRule2) FwPolicy.Rules.Item(ruleName);
return rule.ApplicationName;
}
catch (Exception)
{
@@ -122,14 +138,7 @@ namespace Netch.Utils
private static int GetFwRulesNumber(string ruleName)
{
// https://stackoverflow.com/a/53601691
var i = 0;
foreach (INetFwRule2 rule in FwPolicy.Rules)
{
if (rule.Name == ruleName)
i++;
}
return i;
return FwPolicy.Rules.Cast<INetFwRule2>().Count(rule => rule.Name == ruleName);
}
#endregion

View File

@@ -5,6 +5,7 @@ namespace Netch.Utils
{
public static class Logging
{
private const string LogFile = "logging\\application.log";
/// <summary>
/// 信息
@@ -12,16 +13,25 @@ namespace Netch.Utils
/// <param name="text">内容</param>
public static void Info(string text)
{
File.AppendAllText("logging\\application.log", $@"[{DateTime.Now}][INFO] {text}{Global.EOF}");
File.AppendAllText(LogFile, $@"[{DateTime.Now}][INFO] {text}{Global.EOF}");
}
/// <summary>
/// 信息
/// </summary>
/// <param name="text">内容</param>
public static void Warning(string text)
{
File.AppendAllText(LogFile, $@"[{DateTime.Now}][WARNING] {text}{Global.EOF}");
}
/// <summary>
/// 错误
/// </summary>
/// <param name="text">内容</param>
public static void Error(string text)
{
File.AppendAllText("logging\\application.log", $@"[{DateTime.Now}][ERROR] {text}{Global.EOF}");
File.AppendAllText(LogFile, $@"[{DateTime.Now}][ERROR] {text}{Global.EOF}");
}
}
}
}

View File

@@ -15,7 +15,7 @@ namespace Netch.Utils
{
return MessageBox.Show(
owner: owner,
text: i18N.Translate(text: text),
text: text,
caption: i18N.Translate(string.IsNullOrWhiteSpace(title) ? (info ? "Information" : "Error") : title),
buttons: confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK,
icon: info ? MessageBoxIcon.Information : MessageBoxIcon.Exclamation);

34
Netch/Utils/PortHelper.cs Normal file
View File

@@ -0,0 +1,34 @@
using System.Linq;
using System.Net.NetworkInformation;
using Netch.Controllers;
namespace Netch.Utils
{
public static class PortHelper
{
/// <summary>
/// 指定类型的端口是否已经被使用了
/// </summary>
/// <param name="port">端口</param>
/// <param name="type">检查端口类型</param>
/// <returns>是否被占用</returns>
public static bool PortInUse(int port, PortType type = PortType.Both)
{
var netInfo = IPGlobalProperties.GetIPGlobalProperties();
var tcpResult = type != PortType.UDP && netInfo.GetActiveTcpListeners().Any(ipEndPoint => !MainController.UsingPorts.Contains(ipEndPoint.Port) && ipEndPoint.Port == port);
var udpResult = type != PortType.TCP && netInfo.GetActiveUdpListeners().Any(ipEndPoint => !MainController.UsingPorts.Contains(ipEndPoint.Port) && ipEndPoint.Port == port);
return tcpResult || udpResult;
}
}
/// <summary>
/// 检查端口类型
/// </summary>
public enum PortType
{
TCP,
UDP,
Both
}
}

View File

@@ -87,7 +87,7 @@ namespace Netch.Utils
if (DnsResult != null)
{
Country = databaseReader.Country(Hostname).Country.IsoCode;
Country = databaseReader.Country(DnsResult).Country.IsoCode;
}
else
{

View File

@@ -26,7 +26,7 @@ namespace Netch.Utils
public static void Load(string langCode)
{
LangCode = langCode;
var text = "";
if (langCode.Equals("System"))
{
@@ -34,8 +34,6 @@ namespace Netch.Utils
langCode = CultureInfo.CurrentCulture.Name;
}
if (langCode == "zh-CN")
{
// 尝试加载内置中文语言
@@ -69,18 +67,30 @@ namespace Netch.Utils
/// </summary>
/// <param name="text">需要翻译的文本</param>
/// <returns>翻译完毕的文本</returns>
public static string Translate(string text)
{
return Data.Contains(text) ? Data[text].ToString() : text;
}
public static string Translate(params string[] text)
public static string Translate(params object[] text)
{
var a = new StringBuilder();
foreach (var t in text)
a.Append(Data.Contains(t) ? Data[t].ToString() : t);
if (t is string)
a.Append(Data.Contains(t) ? Data[t].ToString() : t);
else
a.Append(t);
return a.ToString();
}
public static string TranslateFormat(string format, params object[] args)
{
for (var i = 0; i < args.Length; i++)
{
if (args[i] is string)
{
args[i] = Translate((string) args[i]);
}
}
return string.Format(Translate(format), args);
}
public static List<string> GetTranslateList()
{
var translateFile = new List<string> {"System", "zh-CN", "en-US"};