mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
44 Commits
1.4.11
...
1.4.12-Bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5c1cdaf83 | ||
|
|
aa581b2586 | ||
|
|
6d6d747da9 | ||
|
|
8c07273e02 | ||
|
|
aa74948074 | ||
|
|
30b8ed9ac5 | ||
|
|
116b8de135 | ||
|
|
13ed6256d1 | ||
|
|
3c648ebc27 | ||
|
|
452b2c312b | ||
|
|
9f27c4bcf9 | ||
|
|
d2f886ef4b | ||
|
|
52ad3b3b80 | ||
|
|
77c3ae59de | ||
|
|
cdafa14ced | ||
|
|
4d66462416 | ||
|
|
3c0a0d5f80 | ||
|
|
3bdabd7acc | ||
|
|
f605bfa437 | ||
|
|
c8f28f29f1 | ||
|
|
525c9c40fa | ||
|
|
8f1f8de906 | ||
|
|
19fe0a5526 | ||
|
|
401e348402 | ||
|
|
6e4cb9a534 | ||
|
|
ccfb3fe4ce | ||
|
|
0a30ce1b52 | ||
|
|
797e34997f | ||
|
|
6439e8394c | ||
|
|
5ffb5a8235 | ||
|
|
eda75dd681 | ||
|
|
56a40665f1 | ||
|
|
394a56dd76 | ||
|
|
e76b0d5c13 | ||
|
|
c1ef32b420 | ||
|
|
f1e3cc505c | ||
|
|
47dd3e2208 | ||
|
|
bc2fa59672 | ||
|
|
6a6de3eeb8 | ||
|
|
ead8318cb0 | ||
|
|
f4b74092bf | ||
|
|
0d341d3766 | ||
|
|
1568c3b498 | ||
|
|
482eaf28b5 |
@@ -1,83 +1,55 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class DNSController
|
||||
public class DNSController : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
public DNSController()
|
||||
{
|
||||
AkaName = "dns Service";
|
||||
MainFile = "unbound";
|
||||
ExtFiles = new[] {"unbound-service.conf", "forward-zone.conf"};
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动DNS服务
|
||||
/// 启动DNS服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Start()
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Starting dns Service")}");
|
||||
if (!Ready) return false;
|
||||
|
||||
Instance = GetProcess("bin\\unbound.exe");
|
||||
Instance.StartInfo.Arguments = "-c unbound-service.conf -v";
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists("bin\\unbound.exe") && !File.Exists("bin\\unbound-service.conf") && !File.Exists("bin\\forward-zone.conf"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\unbound.exe";
|
||||
|
||||
Instance.StartInfo.Arguments = "-c unbound-service.conf -v";
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
Logging.Info("dns-unbound 启动完毕");
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info("dns-unbound 进程出错");
|
||||
Stop();
|
||||
Logging.Error("dns-unbound 进程出错:\n" + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
WriteLog(e);
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
public override void Stop()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
if (File.Exists("logging\\dns-unbound.log"))
|
||||
{
|
||||
File.Delete("logging\\dns-unbound.log");
|
||||
}
|
||||
File.AppendAllText("logging\\dns-unbound.log", $"{e.Data}\r\n");
|
||||
}
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Netch/Controllers/EncryptedProxy/SSController.cs
Normal file
106
Netch/Controllers/EncryptedProxy/SSController.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class SSController : EncryptedProxy
|
||||
{
|
||||
public SSController()
|
||||
{
|
||||
MainFile = "Shadowsocks";
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
//从DLL启动Shaowsocks
|
||||
if (Global.Settings.BootShadowsocksFromDLL && (mode.Type == 0 || mode.Type == 1 || mode.Type == 2 || mode.Type == 3))
|
||||
{
|
||||
State = State.Starting;
|
||||
var client = Encoding.UTF8.GetBytes($"0.0.0.0:{Global.Settings.Socks5LocalPort}");
|
||||
var remote = Encoding.UTF8.GetBytes($"{server.Hostname}:{server.Port}");
|
||||
var passwd = Encoding.UTF8.GetBytes($"{server.Password}");
|
||||
var method = Encoding.UTF8.GetBytes($"{server.EncryptMethod}");
|
||||
if (!NativeMethods.Shadowsocks.Info(client, remote, passwd, method))
|
||||
{
|
||||
State = State.Stopped;
|
||||
Logging.Error("DLL SS INFO 设置失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS INFO 设置成功!");
|
||||
|
||||
if (!NativeMethods.Shadowsocks.Start())
|
||||
{
|
||||
State = State.Stopped;
|
||||
Logging.Error("DLL SS 启动失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS 启动成功!");
|
||||
State = State.Started;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Ready) return false;
|
||||
Instance = GetProcess("bin\\Shadowsocks.exe");
|
||||
|
||||
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))
|
||||
Instance.StartInfo.Arguments += $" --plugin {server.Plugin} --plugin-opts \"{server.PluginOption}\"";
|
||||
if (mode.BypassChina) Instance.StartInfo.Arguments += " --acl default.acl";
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == State.Started) return true;
|
||||
|
||||
if (State == State.Stopped)
|
||||
{
|
||||
Logging.Error("SS 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Error("SS 进程启动超时");
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSController 停止
|
||||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
if (Global.Settings.BootShadowsocksFromDLL) NativeMethods.Shadowsocks.Stop();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Netch/Controllers/EncryptedProxy/SSRController.cs
Normal file
88
Netch/Controllers/EncryptedProxy/SSRController.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class SSRController : EncryptedProxy
|
||||
{
|
||||
public SSRController()
|
||||
{
|
||||
MainFile = "ShadowsocksR";
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
if (!Ready) return false;
|
||||
|
||||
Instance = GetProcess("bin\\ShadowsocksR.exe");
|
||||
Instance.StartInfo.FileName = "bin\\ShadowsocksR.exe";
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
Instance.StartInfo.Arguments = $"-s {server.Hostname} -p {server.Port} -k \"{server.Password}\" -m {server.EncryptMethod} -t 120";
|
||||
|
||||
if (!string.IsNullOrEmpty(server.Protocol))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -O {server.Protocol}";
|
||||
|
||||
if (!string.IsNullOrEmpty(server.ProtocolParam)) Instance.StartInfo.Arguments += $" -G \"{server.ProtocolParam}\"";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(server.OBFS))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -o {server.OBFS}";
|
||||
|
||||
if (!string.IsNullOrEmpty(server.OBFSParam)) Instance.StartInfo.Arguments += $" -g \"{server.OBFSParam}\"";
|
||||
}
|
||||
|
||||
Instance.StartInfo.Arguments += $" -b {Global.Settings.LocalAddress} -l {Global.Settings.Socks5LocalPort} -u";
|
||||
|
||||
if (mode.BypassChina) Instance.StartInfo.Arguments += " --acl default.acl";
|
||||
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == State.Started) return true;
|
||||
|
||||
if (State == State.Stopped)
|
||||
{
|
||||
Logging.Error("SSR 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Error("SSR 进程启动超时");
|
||||
Stop();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Netch/Controllers/EncryptedProxy/TrojanController.cs
Normal file
82
Netch/Controllers/EncryptedProxy/TrojanController.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TrojanController : EncryptedProxy
|
||||
{
|
||||
public TrojanController()
|
||||
{
|
||||
MainFile = "Trojan";
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
if (!Ready) return false;
|
||||
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new Trojan
|
||||
{
|
||||
local_addr = Global.Settings.LocalAddress,
|
||||
local_port = Global.Settings.Socks5LocalPort,
|
||||
remote_addr = server.Hostname,
|
||||
remote_port = server.Port,
|
||||
password = new List<string>
|
||||
{
|
||||
server.Password
|
||||
}
|
||||
}));
|
||||
|
||||
Instance = GetProcess("bin\\Trojan.exe");
|
||||
Instance.StartInfo.Arguments = "-c ..\\data\\last.json";
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == State.Started) return true;
|
||||
|
||||
if (State == State.Stopped)
|
||||
{
|
||||
Logging.Error("Trojan 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Error("Trojan 进程启动超时");
|
||||
Stop();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
224
Netch/Controllers/EncryptedProxy/VMessController.cs
Normal file
224
Netch/Controllers/EncryptedProxy/VMessController.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using VMess = Netch.Models.Information.VMess;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class VMessController : EncryptedProxy
|
||||
{
|
||||
public VMessController()
|
||||
{
|
||||
MainFile = "v2ray";
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
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>
|
||||
{
|
||||
new VMess.Inbounds
|
||||
{
|
||||
settings = new VMess.InboundSettings(),
|
||||
port = Global.Settings.Socks5LocalPort,
|
||||
listen = Global.Settings.LocalAddress
|
||||
}
|
||||
},
|
||||
outbounds = new List<VMess.Outbounds>
|
||||
{
|
||||
new VMess.Outbounds
|
||||
{
|
||||
settings = new VMess.OutboundSettings
|
||||
{
|
||||
vnext = new List<VMess.VNext>
|
||||
{
|
||||
new VMess.VNext
|
||||
{
|
||||
address = server.Hostname,
|
||||
port = server.Port,
|
||||
users = new List<VMess.User>
|
||||
{
|
||||
new VMess.User
|
||||
{
|
||||
id = server.UserID,
|
||||
alterId = server.AlterID,
|
||||
security = server.EncryptMethod
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
streamSettings = new VMess.StreamSettings
|
||||
{
|
||||
network = server.TransferProtocol,
|
||||
security = server.TLSSecure ? "tls" : "",
|
||||
wsSettings = server.TransferProtocol == "ws"
|
||||
? new VMess.WebSocketSettings
|
||||
{
|
||||
path = server.Path == "" ? "/" : server.Path,
|
||||
headers = new VMess.WSHeaders
|
||||
{
|
||||
Host = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
}
|
||||
: null,
|
||||
tcpSettings = server.FakeType == "http"
|
||||
? new VMess.TCPSettings
|
||||
{
|
||||
header = new VMess.TCPHeaders
|
||||
{
|
||||
type = server.FakeType,
|
||||
request = new VMess.TCPRequest
|
||||
{
|
||||
path = server.Path == "" ? "/" : server.Path,
|
||||
headers = new VMess.TCPRequestHeaders
|
||||
{
|
||||
Host = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
kcpSettings = server.TransferProtocol == "kcp"
|
||||
? new VMess.KCPSettings
|
||||
{
|
||||
header = new VMess.TCPHeaders
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
}
|
||||
: null,
|
||||
quicSettings = server.TransferProtocol == "quic"
|
||||
? new VMess.QUICSettings
|
||||
{
|
||||
security = server.QUICSecure,
|
||||
key = server.QUICSecret,
|
||||
header = new VMess.TCPHeaders
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
}
|
||||
: null,
|
||||
httpSettings = server.TransferProtocol == "h2"
|
||||
? new VMess.HTTPSettings
|
||||
{
|
||||
host = server.Host == "" ? server.Hostname : server.Host,
|
||||
path = server.Path == "" ? "/" : server.Path
|
||||
}
|
||||
: null,
|
||||
tlsSettings = new VMess.TLSSettings
|
||||
{
|
||||
allowInsecure = true,
|
||||
serverName = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
},
|
||||
mux = new VMess.OutboundMux
|
||||
{
|
||||
enabled = server.UseMux
|
||||
}
|
||||
},
|
||||
mode.Type == 0 || mode.Type == 1 || mode.Type == 2
|
||||
? new VMess.Outbounds
|
||||
{
|
||||
tag = "TUNTAP",
|
||||
protocol = "freedom"
|
||||
}
|
||||
: new VMess.Outbounds
|
||||
{
|
||||
tag = "direct",
|
||||
protocol = "freedom"
|
||||
}
|
||||
},
|
||||
routing = new VMess.Routing
|
||||
{
|
||||
rules = new List<VMess.RoutingRules>
|
||||
{
|
||||
mode.BypassChina
|
||||
? new VMess.RoutingRules
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
{
|
||||
"geoip:cn",
|
||||
"geoip:private"
|
||||
},
|
||||
domain = new List<string>
|
||||
{
|
||||
"geosite:cn"
|
||||
},
|
||||
outboundTag = "direct"
|
||||
}
|
||||
: new VMess.RoutingRules
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
{
|
||||
"geoip:private"
|
||||
},
|
||||
outboundTag = "direct"
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
Instance = GetProcess("bin\\v2ray.exe");
|
||||
Instance.StartInfo.Arguments = "-config ..\\data\\last.json";
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == State.Started)
|
||||
{
|
||||
if (File.Exists("data\\last.json")) File.Delete("data\\last.json");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (State == State.Stopped)
|
||||
{
|
||||
Logging.Error("V2Ray 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Error("V2Ray 进程启动超时");
|
||||
Stop();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class HTTPController
|
||||
{
|
||||
/// <summary>
|
||||
/// 实例
|
||||
/// </summary>
|
||||
public PrivoxyController pPrivoxyController = new PrivoxyController();
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (server.Type == "Socks5")
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pPrivoxyController.Start(server, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrivoxyController.Start(server, mode);
|
||||
}
|
||||
|
||||
if (mode.Type != 5)
|
||||
{
|
||||
NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", "<local>");
|
||||
|
||||
// HTTP 系统代理模式,启动系统代理
|
||||
/*
|
||||
using (var registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true))
|
||||
{
|
||||
registry.SetValue("ProxyEnable", 1);
|
||||
registry.SetValue("ProxyServer", $"127.0.0.1:{Global.Settings.HTTPLocalPort}");
|
||||
|
||||
Win32Native.InternetSetOption(IntPtr.Zero, 39, IntPtr.Zero, 0);
|
||||
Win32Native.InternetSetOption(IntPtr.Zero, 37, IntPtr.Zero, 0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (System.Windows.Forms.MessageBox.Show(i18N.Translate("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?"), i18N.Translate("Information"), MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
|
||||
{
|
||||
System.Diagnostics.Process.Start("https://netch.org/#/?id=%e4%be%9d%e8%b5%96");
|
||||
}
|
||||
Utils.Logging.Info("设置系统代理失败" + e.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
pPrivoxyController.Stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
|
||||
NativeMethods.SetDIRECT();
|
||||
|
||||
/*
|
||||
using (var registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true))
|
||||
{
|
||||
registry.SetValue("ProxyEnable", 0);
|
||||
registry.DeleteValue("ProxyServer", false);
|
||||
|
||||
Win32Native.InternetSetOption(IntPtr.Zero, 39, IntPtr.Zero, 0);
|
||||
Win32Native.InternetSetOption(IntPtr.Zero, 37, IntPtr.Zero, 0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
150
Netch/Controllers/Interface/Controller.cs
Normal file
150
Netch/Controllers/Interface/Controller.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public abstract class Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制器名
|
||||
/// <param />
|
||||
/// 未赋值会在 <see cref="InitCheck" /> 赋值为 <see cref="MainFile" />
|
||||
/// </summary>
|
||||
public string AkaName;
|
||||
|
||||
/// <summary>
|
||||
/// 其他需要文件
|
||||
/// </summary>
|
||||
protected string[] ExtFiles;
|
||||
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 主程序名(不含扩展名)
|
||||
/// </summary>
|
||||
public string MainFile;
|
||||
|
||||
/// <summary>
|
||||
/// 运行检查, 由 <see cref="InitCheck()" /> 赋值
|
||||
/// </summary>
|
||||
public bool Ready;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
protected State State = State.Waiting;
|
||||
|
||||
public abstract void Stop();
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
protected void StopInstance()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance == null || Instance.HasExited) return;
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"停止 {MainFile}.exe 错误:\n" + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 杀残留进程,清除日志,检查文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected void InitCheck()
|
||||
{
|
||||
if (string.IsNullOrEmpty(AkaName)) AkaName = MainFile;
|
||||
|
||||
var result = false;
|
||||
// 杀残留
|
||||
MainController.KillProcessByName(MainFile);
|
||||
// 清日志
|
||||
try
|
||||
{
|
||||
if (File.Exists($"logging\\{AkaName}.log")) File.Delete($"logging\\{AkaName}.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)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(std.Data)) return false;
|
||||
try
|
||||
|
||||
{
|
||||
File.AppendAllText($"logging\\{AkaName}.log", $@"{std.Data}{Global.EOF}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"写入{AkaName}日志错误:\n" + e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Process GetProcess(string path = null, bool redirectStd = true)
|
||||
{
|
||||
var p = new Process
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
Arguments = "",
|
||||
WorkingDirectory = $"{Global.NetchDir}\\bin",
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardError = redirectStd,
|
||||
RedirectStandardInput = redirectStd,
|
||||
RedirectStandardOutput = redirectStd,
|
||||
UseShellExecute = false
|
||||
},
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
if (path != null) p.StartInfo.FileName = Path.GetFullPath(path);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Netch/Controllers/Interface/EncryptedProxy.cs
Normal file
18
Netch/Controllers/Interface/EncryptedProxy.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Diagnostics;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public abstract class EncryptedProxy : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public abstract bool Start(Server server, Mode mode);
|
||||
|
||||
public abstract void OnOutputDataReceived(object sender, DataReceivedEventArgs e);
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Interface/ModeController.cs
Normal file
15
Netch/Controllers/Interface/ModeController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public abstract class ModeController : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public abstract bool Start(Server server, Mode mode);
|
||||
}
|
||||
}
|
||||
@@ -1,283 +1,142 @@
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class MainController
|
||||
{
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern UInt32 FlushDNSResolverCache();
|
||||
public static Process GetProcess()
|
||||
{
|
||||
var process = new Process();
|
||||
process.StartInfo.WorkingDirectory = string.Format("{0}\\bin", Directory.GetCurrentDirectory());
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.StartInfo.RedirectStandardInput = true;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.EnableRaisingEvents = true;
|
||||
public EncryptedProxy pEncryptedProxyController;
|
||||
|
||||
return process;
|
||||
}
|
||||
public ModeController pModeController;
|
||||
|
||||
/// <summary>
|
||||
/// SS 控制器
|
||||
/// </summary>
|
||||
public SSController pSSController;
|
||||
|
||||
/// <summary>
|
||||
/// SSR 控制器
|
||||
/// </summary>
|
||||
public SSRController pSSRController;
|
||||
|
||||
/// <summary>
|
||||
/// V2Ray 控制器
|
||||
/// </summary>
|
||||
public VMessController pVMessController;
|
||||
|
||||
/// <summary>
|
||||
/// Trojan 控制器
|
||||
/// </summary>
|
||||
public TrojanController pTrojanController;
|
||||
|
||||
/// <summary>
|
||||
/// NF 控制器
|
||||
/// </summary>
|
||||
public NFController pNFController;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 控制器
|
||||
/// </summary>
|
||||
public HTTPController pHTTPController;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP 控制器
|
||||
/// </summary>
|
||||
public TUNTAPController pTUNTAPController;
|
||||
|
||||
/// <summary>
|
||||
/// NTT 控制器
|
||||
/// NTT 控制器
|
||||
/// </summary>
|
||||
public NTTController pNTTController;
|
||||
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint FlushDNSResolverCache();
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
public bool Start(Server server, Mode mode)
|
||||
{
|
||||
pNTTController ??= new NTTController();
|
||||
FlushDNSResolverCache();
|
||||
|
||||
var result = false;
|
||||
switch (server.Type)
|
||||
if (server.Type == "Socks5")
|
||||
{
|
||||
case "Socks5":
|
||||
if (mode.Type == 4)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
case "SS":
|
||||
KillProcess("Shadowsocks");
|
||||
if (pSSController == null)
|
||||
{
|
||||
pSSController = new SSController();
|
||||
}
|
||||
result = pSSController.Start(server, mode);
|
||||
break;
|
||||
case "SSR":
|
||||
KillProcess("ShadowsocksR");
|
||||
if (pSSRController == null)
|
||||
{
|
||||
pSSRController = new SSRController();
|
||||
}
|
||||
result = pSSRController.Start(server, mode);
|
||||
break;
|
||||
case "VMess":
|
||||
KillProcess("v2ray");
|
||||
if (pVMessController == null)
|
||||
{
|
||||
pVMessController = new VMessController();
|
||||
}
|
||||
result = pVMessController.Start(server, mode);
|
||||
break;
|
||||
case "Trojan":
|
||||
KillProcess("Trojan");
|
||||
if (pTrojanController == null)
|
||||
{
|
||||
pTrojanController = new TrojanController();
|
||||
}
|
||||
result = pTrojanController.Start(server, mode);
|
||||
break;
|
||||
result = mode.Type != 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (server.Type)
|
||||
{
|
||||
case "SS":
|
||||
pEncryptedProxyController = new SSController();
|
||||
break;
|
||||
case "SSR":
|
||||
pEncryptedProxyController = new SSRController();
|
||||
break;
|
||||
case "VMess":
|
||||
pEncryptedProxyController = new VMessController();
|
||||
break;
|
||||
case "Trojan":
|
||||
pEncryptedProxyController = new TrojanController();
|
||||
break;
|
||||
}
|
||||
|
||||
MainForm.Instance.StatusText(i18N.Translate("Starting ", pEncryptedProxyController.AkaName));
|
||||
if (pEncryptedProxyController.Ready) result = pEncryptedProxyController.Start(server, mode);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (mode.Type == 0)
|
||||
// 加密代理已启动
|
||||
switch (mode.Type)
|
||||
{
|
||||
if (pNFController == null)
|
||||
{
|
||||
pNFController = new NFController();
|
||||
}
|
||||
if (pNTTController == null)
|
||||
{
|
||||
pNTTController = new NTTController();
|
||||
}
|
||||
// 进程代理模式,启动 NF 控制器
|
||||
result = pNFController.Start(server, mode, false);
|
||||
if (!result)
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Restarting Redirector")}");
|
||||
Utils.Logging.Info("正常启动失败后尝试停止驱动服务再重新启动");
|
||||
//正常启动失败后尝试停止驱动服务再重新启动
|
||||
result = pNFController.Start(server, mode, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => pNTTController.Start());
|
||||
}
|
||||
case 0: // 进程代理模式
|
||||
pModeController = new NFController();
|
||||
break;
|
||||
case 1: // TUN/TAP 黑名单代理模式
|
||||
case 2: // TUN/TAP 白名单代理模式
|
||||
pModeController = new TUNTAPController();
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
pModeController = new HTTPController();
|
||||
break;
|
||||
case 4: // Socks5 代理模式,不需要启动额外的Server
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
else if (mode.Type == 1)
|
||||
|
||||
if (pModeController != null && pModeController.Ready)
|
||||
{
|
||||
if (pTUNTAPController == null)
|
||||
{
|
||||
pTUNTAPController = new TUNTAPController();
|
||||
}
|
||||
if (pNTTController == null)
|
||||
{
|
||||
pNTTController = new NTTController();
|
||||
}
|
||||
// TUN/TAP 黑名单代理模式,启动 TUN/TAP 控制器
|
||||
result = pTUNTAPController.Start(server, mode);
|
||||
if (result)
|
||||
{
|
||||
Task.Run(() => pNTTController.Start());
|
||||
}
|
||||
MainForm.Instance.StatusText(i18N.Translate("Starting ", pModeController.AkaName));
|
||||
result = pModeController.Start(server, mode);
|
||||
}
|
||||
else if (mode.Type == 2)
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
if (pTUNTAPController == null)
|
||||
{
|
||||
pTUNTAPController = new TUNTAPController();
|
||||
}
|
||||
if (pNTTController == null)
|
||||
{
|
||||
pNTTController = new NTTController();
|
||||
}
|
||||
// TUN/TAP 白名单代理模式,启动 TUN/TAP 控制器
|
||||
result = pTUNTAPController.Start(server, mode);
|
||||
if (result)
|
||||
{
|
||||
Task.Run(() => pNTTController.Start());
|
||||
}
|
||||
}
|
||||
else if (mode.Type == 3 || mode.Type == 5)
|
||||
{
|
||||
if (pHTTPController == null)
|
||||
{
|
||||
pHTTPController = new HTTPController();
|
||||
}
|
||||
// HTTP 系统代理和 Socks5 和 HTTP 代理模式,启动 HTTP 控制器
|
||||
result = pHTTPController.Start(server, mode);
|
||||
}
|
||||
else if (mode.Type == 4)
|
||||
{
|
||||
// Socks5 代理模式,不需要启动额外的控制器
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
if (result)
|
||||
Task.Run(() =>
|
||||
{
|
||||
MainForm.Instance.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);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
if (!result) Stop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (pSSController != null)
|
||||
{
|
||||
pSSController.Stop();
|
||||
}
|
||||
else if (pSSRController != null)
|
||||
{
|
||||
pSSRController.Stop();
|
||||
}
|
||||
else if (pVMessController != null)
|
||||
{
|
||||
pVMessController.Stop();
|
||||
}
|
||||
else if (pTrojanController != null)
|
||||
{
|
||||
pTrojanController.Stop();
|
||||
}
|
||||
|
||||
if (pNFController != null)
|
||||
{
|
||||
pNFController.Stop();
|
||||
}
|
||||
else if (pTUNTAPController != null)
|
||||
{
|
||||
pTUNTAPController.Stop();
|
||||
}
|
||||
else if (pHTTPController != null)
|
||||
{
|
||||
pHTTPController.Stop();
|
||||
}
|
||||
|
||||
if (pNTTController != null)
|
||||
{
|
||||
pNTTController.Stop();
|
||||
}
|
||||
pEncryptedProxyController?.Stop();
|
||||
pModeController?.Stop();
|
||||
}
|
||||
|
||||
public void KillProcess(string name)
|
||||
public static void KillProcessByName(string name)
|
||||
{
|
||||
var processes = Process.GetProcessesByName(name);
|
||||
foreach (var p in processes)
|
||||
{
|
||||
if (IsChildProcess(p, name))
|
||||
{
|
||||
p.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsChildProcess(Process process, string name)
|
||||
{
|
||||
bool result;
|
||||
try
|
||||
{
|
||||
var FileName = (Directory.GetCurrentDirectory() + "\\bin\\" + name + ".exe").ToLower();
|
||||
var procFileName = process.MainModule.FileName.ToLower();
|
||||
result = FileName.Equals(procFileName, StringComparison.Ordinal);
|
||||
foreach (var p in Process.GetProcessesByName(name))
|
||||
if (p.MainModule != null && p.MainModule.FileName.StartsWith(Global.NetchDir))
|
||||
p.Kill();
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.Message);
|
||||
result = false;
|
||||
Logging.Error($"结束进程 {name} 错误:\n" + e);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Netch/Controllers/Mode/HTTPController.cs
Normal file
102
Netch/Controllers/Mode/HTTPController.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class HTTPController : ModeController
|
||||
{
|
||||
/// <summary>
|
||||
/// 实例
|
||||
/// </summary>
|
||||
public PrivoxyController pPrivoxyController = new PrivoxyController();
|
||||
|
||||
private string prevBypass, prevHTTP, prevPAC;
|
||||
private bool prevEnabled;
|
||||
|
||||
public HTTPController()
|
||||
{
|
||||
AkaName = "HTTP";
|
||||
Ready = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
if (!Ready) return false;
|
||||
|
||||
RecordPrevious();
|
||||
try
|
||||
{
|
||||
if (server.Type == "Socks5")
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password)) return false;
|
||||
|
||||
pPrivoxyController.Start(server, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrivoxyController.Start(server, mode);
|
||||
}
|
||||
|
||||
if (mode.Type != 5) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", "<local>");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (MessageBoxX.Show(i18N.Translate("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?"), confirm: true) == DialogResult.OK) Process.Start("https://netch.org/#/?id=%e4%be%9d%e8%b5%96");
|
||||
|
||||
Logging.Error("设置系统代理失败" + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RecordPrevious()
|
||||
{
|
||||
var registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
|
||||
if (registry == null)
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevPAC = prevHTTP = prevBypass = "";
|
||||
return;
|
||||
}
|
||||
|
||||
prevPAC = registry.GetValue("AutoConfigURL")?.ToString() ?? "";
|
||||
if ((registry.GetValue("ProxyEnable")?.Equals(1) ?? false) || prevPAC != "") prevEnabled = true;
|
||||
|
||||
prevHTTP = registry.GetValue("ProxyServer")?.ToString() ?? "";
|
||||
prevBypass = registry.GetValue("ProxyOverride")?.ToString() ?? "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
pPrivoxyController.Stop();
|
||||
|
||||
NativeMethods.SetGlobal(prevHTTP, prevBypass);
|
||||
if (prevPAC != "")
|
||||
NativeMethods.SetURL(prevPAC);
|
||||
if (!prevEnabled)
|
||||
NativeMethods.SetDIRECT();
|
||||
prevEnabled = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("停止HTTP控制器错误:\n" + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
273
Netch/Controllers/Mode/NFController.cs
Normal file
273
Netch/Controllers/Mode/NFController.cs
Normal file
@@ -0,0 +1,273 @@
|
||||
using System;
|
||||
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;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class NFController : ModeController
|
||||
{
|
||||
private static readonly ServiceController NFService = new ServiceController("netfilter2");
|
||||
|
||||
private static readonly string BinDriver = "";
|
||||
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
|
||||
|
||||
public static string DriverVersion(string file)
|
||||
{
|
||||
return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : "";
|
||||
}
|
||||
|
||||
static NFController()
|
||||
{
|
||||
// 生成系统版本
|
||||
var winNTver = $"{Environment.OSVersion.Version.Major.ToString()}.{Environment.OSVersion.Version.Minor.ToString()}";
|
||||
switch (winNTver)
|
||||
{
|
||||
case "10.0":
|
||||
BinDriver = "Win-10.sys";
|
||||
break;
|
||||
case "6.3":
|
||||
case "6.2":
|
||||
BinDriver = "Win-8.sys";
|
||||
break;
|
||||
case "6.1":
|
||||
case "6.0":
|
||||
BinDriver = "Win-7.sys";
|
||||
break;
|
||||
default:
|
||||
Logging.Error($"不支持的系统版本:{winNTver}");
|
||||
return;
|
||||
}
|
||||
|
||||
BinDriver = "bin\\" + BinDriver;
|
||||
}
|
||||
|
||||
public NFController()
|
||||
{
|
||||
MainFile = "Redirector";
|
||||
ExtFiles = new[] {Path.GetFileName(BinDriver)};
|
||||
InitCheck();
|
||||
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
InstallDriver();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
if (!CheckDriverReady())
|
||||
{
|
||||
if (File.Exists(SystemDriver))
|
||||
UninstallDriver();
|
||||
if (!InstallDriver())
|
||||
return false;
|
||||
}
|
||||
|
||||
var processList = "";
|
||||
foreach (var proc in mode.Rule)
|
||||
processList += proc + ",";
|
||||
processList += "NTT.exe";
|
||||
|
||||
Instance = GetProcess("bin\\Redirector.exe");
|
||||
if (server.Type != "Socks5")
|
||||
{
|
||||
Instance.StartInfo.Arguments += $"-r 127.0.0.1:{Global.Settings.Socks5LocalPort} -p \"{processList}\"";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var result = DNS.Lookup(server.Hostname);
|
||||
if (result == null)
|
||||
{
|
||||
Logging.Info("无法解析服务器 IP 地址");
|
||||
return false;
|
||||
}
|
||||
|
||||
Instance.StartInfo.Arguments += $"-r {result}:{server.Port} -p \"{processList}\"";
|
||||
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password)) Instance.StartInfo.Arguments += $" -username \"{server.Username}\" -password \"{server.Password}\"";
|
||||
}
|
||||
|
||||
Instance.StartInfo.Arguments += $" -t {Global.Settings.RedirectorTCPPort}";
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
|
||||
for (var j = 0; j < 40; j++)
|
||||
{
|
||||
Thread.Sleep(250);
|
||||
|
||||
if (State == State.Started) return true;
|
||||
}
|
||||
|
||||
Logging.Error("NF 进程启动超时");
|
||||
Stop();
|
||||
if (!RestartService()) return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool RestartService()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (NFService.Status)
|
||||
{
|
||||
// 启动驱动服务
|
||||
case ServiceControllerStatus.Running:
|
||||
// 防止其他程序占用 重置 NF 百万连接数限制
|
||||
NFService.Stop();
|
||||
NFService.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
MainForm.Instance.StatusText(i18N.Translate("Starting netfilter2 Service"));
|
||||
NFService.Start();
|
||||
break;
|
||||
case ServiceControllerStatus.Stopped:
|
||||
MainForm.Instance.StatusText(i18N.Translate("Starting netfilter2 Service"));
|
||||
NFService.Start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("启动驱动服务失败:\n" + e);
|
||||
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result != NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Logging.Error($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("注册驱动成功");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CheckDriverReady()
|
||||
{
|
||||
// 检查驱动是否存在
|
||||
if (!File.Exists(SystemDriver)) return false;
|
||||
|
||||
// 检查驱动版本号
|
||||
return DriverVersion(SystemDriver) == DriverVersion(BinDriver);
|
||||
}
|
||||
|
||||
public static bool UninstallDriver()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (NFService.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
NFService.Stop();
|
||||
NFService.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!File.Exists(SystemDriver)) return true;
|
||||
try
|
||||
{
|
||||
NFAPI.nf_unRegisterDriver("netfilter2");
|
||||
|
||||
File.Delete(SystemDriver);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool InstallDriver()
|
||||
{
|
||||
Logging.Info("安装驱动中");
|
||||
try
|
||||
{
|
||||
File.Copy(BinDriver, SystemDriver);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("驱动复制失败\n" + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
MainForm.Instance.StatusText(i18N.Translate("Register driver"));
|
||||
// 注册驱动文件
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result == NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Logging.Info($"驱动安装成功,当前驱动版本:{DriverVersion(DriverVersion(SystemDriver))}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流量变动事件
|
||||
/// </summary>
|
||||
public event BandwidthUpdateHandler OnBandwidthUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// 流量变动处理器
|
||||
/// </summary>
|
||||
/// <param name="upload">上传</param>
|
||||
/// <param name="download">下载</param>
|
||||
public delegate void BandwidthUpdateHandler(long upload, long download);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,43 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
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;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNTAPController
|
||||
public class TUNTAPController : ModeController
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例(tun2socks)
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
// ByPassLan IP
|
||||
private readonly List<string> _bypassLanIPs = new List<string> {"10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16"};
|
||||
|
||||
private Mode _savedMode = new Mode();
|
||||
private Server _savedServer = new Server();
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// 服务器 IP 地址
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
private IPAddress[] _serverAddresses = new IPAddress[0];
|
||||
|
||||
/// <summary>
|
||||
/// 服务器 IP 地址
|
||||
/// </summary>
|
||||
public IPAddress[] ServerAddresses = new IPAddress[0];
|
||||
|
||||
/// <summary>
|
||||
/// 保存传入的规则
|
||||
/// </summary>
|
||||
public Models.Server SavedServer = new Models.Server();
|
||||
public Models.Mode SavedMode = new Models.Mode();
|
||||
|
||||
/// <summary>
|
||||
/// 本地 DNS 服务控制器
|
||||
/// 本地 DNS 服务控制器
|
||||
/// </summary>
|
||||
public DNSController pDNSController = new DNSController();
|
||||
|
||||
// ByPassLan IP
|
||||
List<string> BypassLanIPs = new List<string>() { "10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16" };
|
||||
public TUNTAPController()
|
||||
{
|
||||
MainFile = "tun2socks";
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置 TUNTAP 适配器
|
||||
@@ -47,19 +45,16 @@ namespace Netch.Controllers
|
||||
public bool Configure()
|
||||
{
|
||||
// 查询服务器 IP 地址
|
||||
var destination = Dns.GetHostAddressesAsync(SavedServer.Hostname);
|
||||
var destination = Dns.GetHostAddressesAsync(_savedServer.Hostname);
|
||||
if (destination.Wait(1000))
|
||||
{
|
||||
if (destination.Result.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (destination.Result.Length == 0) return false;
|
||||
|
||||
ServerAddresses = destination.Result;
|
||||
_serverAddresses = destination.Result;
|
||||
}
|
||||
|
||||
// 搜索出口
|
||||
return Utils.Configuration.SearchOutbounds();
|
||||
return SearchOutbounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,22 +62,18 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
public bool SetupBypass()
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("SetupBypass")}");
|
||||
MainForm.Instance.StatusText(i18N.Translate("SetupBypass"));
|
||||
Logging.Info("设置绕行规则 → 设置让服务器 IP 走直连");
|
||||
// 让服务器 IP 走直连
|
||||
foreach (var address in ServerAddresses)
|
||||
{
|
||||
foreach (var address in _serverAddresses)
|
||||
if (!IPAddress.IsLoopback(address))
|
||||
{
|
||||
NativeMethods.CreateRoute(address.ToString(), 32, Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理模式的绕过中国
|
||||
if (SavedMode.BypassChina)
|
||||
if (_savedMode.BypassChina)
|
||||
{
|
||||
Logging.Info("设置绕行规则 → 处理模式的绕过中国");
|
||||
using (var sr = new StringReader(Encoding.UTF8.GetString(Properties.Resources.CNIP)))
|
||||
using (var sr = new StringReader(Encoding.UTF8.GetString(Resources.CNIP)))
|
||||
{
|
||||
string text;
|
||||
|
||||
@@ -102,26 +93,20 @@ namespace Netch.Controllers
|
||||
var info = ip.Split('/');
|
||||
var address = IPAddress.Parse(info[0]);
|
||||
|
||||
if (!IPAddress.IsLoopback(address))
|
||||
{
|
||||
NativeMethods.CreateRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
if (!IPAddress.IsLoopback(address)) NativeMethods.CreateRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
|
||||
Logging.Info("设置绕行规则 → 处理绕过局域网 IP");
|
||||
// 处理绕过局域网 IP
|
||||
foreach (var ip in BypassLanIPs)
|
||||
foreach (var ip in _bypassLanIPs)
|
||||
{
|
||||
var info = ip.Split('/');
|
||||
var address = IPAddress.Parse(info[0]);
|
||||
|
||||
if (!IPAddress.IsLoopback(address))
|
||||
{
|
||||
NativeMethods.CreateRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
if (!IPAddress.IsLoopback(address)) NativeMethods.CreateRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
|
||||
if (SavedMode.Type == 2) // 处理仅规则内走直连
|
||||
if (_savedMode.Type == 2) // 处理仅规则内走直连
|
||||
{
|
||||
Logging.Info("设置绕行规则 → 处理仅规则内走直连");
|
||||
// 将 TUN/TAP 网卡权重放到最高
|
||||
@@ -142,74 +127,58 @@ namespace Netch.Controllers
|
||||
// 创建默认路由
|
||||
if (!NativeMethods.CreateRoute("0.0.0.0", 0, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index, 10))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
State = State.Stopped;
|
||||
|
||||
foreach (var address in ServerAddresses)
|
||||
{
|
||||
NativeMethods.DeleteRoute(address.ToString(), 32, Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
foreach (var address in _serverAddresses) NativeMethods.DeleteRoute(address.ToString(), 32, Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("设置绕行规则 → 创建规则路由");
|
||||
// 创建规则路由
|
||||
foreach (var ip in SavedMode.Rule)
|
||||
foreach (var ip in _savedMode.Rule)
|
||||
{
|
||||
var info = ip.Split('/');
|
||||
|
||||
if (info.Length == 2)
|
||||
{
|
||||
if (int.TryParse(info[1], out var prefix))
|
||||
{
|
||||
NativeMethods.CreateRoute(info[0], prefix, Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (SavedMode.Type == 1) // 处理仅规则内走代理
|
||||
else if (_savedMode.Type == 1) // 处理仅规则内走代理
|
||||
{
|
||||
Logging.Info("设置绕行规则->处理仅规则内走代理");
|
||||
foreach (var ip in SavedMode.Rule)
|
||||
foreach (var ip in _savedMode.Rule)
|
||||
{
|
||||
var info = ip.Split('/');
|
||||
|
||||
if (info.Length == 2)
|
||||
{
|
||||
if (int.TryParse(info[1], out var prefix))
|
||||
{
|
||||
NativeMethods.CreateRoute(info[0], prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP,自己记录解析了返回的 IP,仅支持默认检测服务器
|
||||
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
|
||||
{
|
||||
try
|
||||
{
|
||||
var nttAddress = Dns.GetHostAddresses(Global.Settings.STUN_Server)[0];
|
||||
if (int.TryParse("32", out var prefix))
|
||||
{
|
||||
NativeMethods.CreateRoute(nttAddress.ToString(), prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefix)) NativeMethods.CreateRoute(nttAddress.ToString(), prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
|
||||
var nttrAddress = Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0];
|
||||
if (int.TryParse("32", out var prefixr))
|
||||
{
|
||||
NativeMethods.CreateRoute(nttrAddress.ToString(), prefixr, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefixr)) NativeMethods.CreateRoute(nttrAddress.ToString(), prefixr, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
|
||||
}
|
||||
}
|
||||
|
||||
//处理DNS代理
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
Logging.Info("设置绕行规则 → 处理自定义 DNS 代理");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
string dns = "";
|
||||
var dns = "";
|
||||
foreach (var value in Global.Settings.TUNTAP.DNS)
|
||||
{
|
||||
dns += value;
|
||||
@@ -218,10 +187,7 @@ namespace Netch.Controllers
|
||||
|
||||
dns = dns.Trim();
|
||||
dns = dns.Substring(0, dns.Length - 1);
|
||||
if (int.TryParse("32", out var prefix))
|
||||
{
|
||||
NativeMethods.CreateRoute(dns, prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefix)) NativeMethods.CreateRoute(dns, prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -235,6 +201,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -244,59 +211,48 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
public bool ClearBypass()
|
||||
{
|
||||
if (SavedMode.Type == 2)
|
||||
if (_savedMode.Type == 2)
|
||||
{
|
||||
NativeMethods.DeleteRoute("0.0.0.0", 0, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index, 10);
|
||||
|
||||
foreach (var ip in SavedMode.Rule)
|
||||
foreach (var ip in _savedMode.Rule)
|
||||
{
|
||||
var info = ip.Split('/');
|
||||
|
||||
if (info.Length == 2)
|
||||
{
|
||||
if (int.TryParse(info[1], out var prefix))
|
||||
{
|
||||
NativeMethods.DeleteRoute(info[0], prefix, Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (SavedMode.Type == 1)
|
||||
else if (_savedMode.Type == 1)
|
||||
{
|
||||
foreach (var ip in SavedMode.Rule)
|
||||
foreach (var ip in _savedMode.Rule)
|
||||
{
|
||||
var info = ip.Split('/');
|
||||
|
||||
if (info.Length == 2)
|
||||
{
|
||||
if (int.TryParse(info[1], out var prefix))
|
||||
{
|
||||
NativeMethods.DeleteRoute(info[0], prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
|
||||
{
|
||||
try
|
||||
{
|
||||
var nttAddress = Dns.GetHostAddresses(Global.Settings.STUN_Server)[0];
|
||||
if (int.TryParse("32", out var prefix))
|
||||
{
|
||||
NativeMethods.DeleteRoute(nttAddress.ToString(), prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefix)) NativeMethods.DeleteRoute(nttAddress.ToString(), prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
|
||||
var nttrAddress = Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0];
|
||||
if (int.TryParse("32", out var prefixr))
|
||||
{
|
||||
NativeMethods.DeleteRoute(nttrAddress.ToString(), prefixr, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefixr)) NativeMethods.DeleteRoute(nttrAddress.ToString(), prefixr, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
string dns = "";
|
||||
var dns = "";
|
||||
foreach (var value in Global.Settings.TUNTAP.DNS)
|
||||
{
|
||||
dns += value;
|
||||
@@ -305,17 +261,11 @@ namespace Netch.Controllers
|
||||
|
||||
dns = dns.Trim();
|
||||
dns = dns.Substring(0, dns.Length - 1);
|
||||
if (int.TryParse("32", out var prefix))
|
||||
{
|
||||
NativeMethods.DeleteRoute(dns, prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefix)) NativeMethods.DeleteRoute(dns, prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (int.TryParse("32", out var prefix))
|
||||
{
|
||||
NativeMethods.DeleteRoute("1.1.1.1", prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
if (int.TryParse("32", out var prefix)) NativeMethods.DeleteRoute("1.1.1.1", prefix, Global.Settings.TUNTAP.Gateway, Global.TUNTAP.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,25 +275,19 @@ namespace Netch.Controllers
|
||||
var info = ip.Split('/');
|
||||
var address = IPAddress.Parse(info[0]);
|
||||
|
||||
if (!IPAddress.IsLoopback(address))
|
||||
{
|
||||
NativeMethods.DeleteRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
if (!IPAddress.IsLoopback(address)) NativeMethods.DeleteRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
foreach (var ip in BypassLanIPs)
|
||||
|
||||
foreach (var ip in _bypassLanIPs)
|
||||
{
|
||||
var info = ip.Split('/');
|
||||
var address = IPAddress.Parse(info[0]);
|
||||
|
||||
if (!IPAddress.IsLoopback(address))
|
||||
{
|
||||
NativeMethods.DeleteRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
if (!IPAddress.IsLoopback(address)) NativeMethods.DeleteRoute(address.ToString(), int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
|
||||
if (SavedMode.BypassChina)
|
||||
{
|
||||
using (var sr = new StringReader(Encoding.UTF8.GetString(Properties.Resources.CNIP)))
|
||||
if (_savedMode.BypassChina)
|
||||
using (var sr = new StringReader(Encoding.UTF8.GetString(Resources.CNIP)))
|
||||
{
|
||||
string text;
|
||||
|
||||
@@ -354,63 +298,31 @@ namespace Netch.Controllers
|
||||
NativeMethods.DeleteRoute(info[0], int.Parse(info[1]), Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var address in ServerAddresses)
|
||||
{
|
||||
foreach (var address in _serverAddresses)
|
||||
if (!IPAddress.IsLoopback(address))
|
||||
{
|
||||
NativeMethods.DeleteRoute(address.ToString(), 32, Global.Adapter.Gateway.ToString(), Global.Adapter.Index);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">配置</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting Tap")}");
|
||||
foreach (var proc in Process.GetProcessesByName("tun2socks"))
|
||||
{
|
||||
try
|
||||
{
|
||||
proc.Kill();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 跳过
|
||||
}
|
||||
}
|
||||
if (!Ready) return false;
|
||||
|
||||
if (!File.Exists("bin\\tun2socks.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
MainForm.Instance.StatusText(i18N.Translate("Starting Tap"));
|
||||
|
||||
if (File.Exists("logging\\tun2socks.log"))
|
||||
{
|
||||
File.Delete("logging\\tun2socks.log");
|
||||
}
|
||||
_savedMode = mode;
|
||||
_savedServer = server;
|
||||
|
||||
SavedMode = mode;
|
||||
SavedServer = server;
|
||||
|
||||
if (!Configure())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Configure()) return false;
|
||||
|
||||
Logging.Info("设置绕行规则");
|
||||
SetupBypass();
|
||||
Logging.Info("设置绕行规则完毕");
|
||||
|
||||
Instance = new Process();
|
||||
Instance.StartInfo.WorkingDirectory = string.Format("{0}\\bin", Directory.GetCurrentDirectory());
|
||||
Instance.StartInfo.FileName = string.Format("{0}\\bin\\tun2socks.exe", Directory.GetCurrentDirectory());
|
||||
Instance = GetProcess("bin\\tun2socks.exe");
|
||||
|
||||
var adapterName = TUNTAP.GetName(Global.TUNTAP.ComponentID);
|
||||
Logging.Info($"tun2sock使用适配器:{adapterName}");
|
||||
|
||||
@@ -434,32 +346,18 @@ namespace Netch.Controllers
|
||||
pDNSController.Start();
|
||||
dns = "127.0.0.1";
|
||||
}
|
||||
if (Global.Settings.TUNTAP.UseFakeDNS)
|
||||
{
|
||||
dns += " -fakeDns";
|
||||
}
|
||||
|
||||
if (Global.Settings.TUNTAP.UseFakeDNS) dns += " -fakeDns";
|
||||
|
||||
if (server.Type == "Socks5")
|
||||
{
|
||||
Instance.StartInfo.Arguments = string.Format("-proxyServer {0}:{1} -tunAddr {2} -tunMask {3} -tunGw {4} -tunDns {5} -tunName \"{6}\"", server.Hostname, server.Port, Global.Settings.TUNTAP.Address, Global.Settings.TUNTAP.Netmask, Global.Settings.TUNTAP.Gateway, dns, adapterName);
|
||||
}
|
||||
Instance.StartInfo.Arguments = $"-proxyServer {server.Hostname}:{server.Port} -tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {dns} -tunName \"{adapterName}\"";
|
||||
else
|
||||
{
|
||||
Instance.StartInfo.Arguments = string.Format("-proxyServer 127.0.0.1:{0} -tunAddr {1} -tunMask {2} -tunGw {3} -tunDns {4} -tunName \"{5}\"", Global.Settings.Socks5LocalPort, Global.Settings.TUNTAP.Address, Global.Settings.TUNTAP.Netmask, Global.Settings.TUNTAP.Gateway, dns, adapterName);
|
||||
}
|
||||
Instance.StartInfo.Arguments = $"-proxyServer 127.0.0.1:{Global.Settings.Socks5LocalPort} -tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {dns} -tunName \"{adapterName}\"";
|
||||
|
||||
Instance.StartInfo.CreateNoWindow = true;
|
||||
Instance.StartInfo.RedirectStandardError = true;
|
||||
Instance.StartInfo.RedirectStandardInput = true;
|
||||
Instance.StartInfo.RedirectStandardOutput = true;
|
||||
Instance.StartInfo.UseShellExecute = false;
|
||||
Instance.EnableRaisingEvents = true;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
|
||||
Logging.Info(Instance.StartInfo.Arguments);
|
||||
|
||||
State = Models.State.Starting;
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginErrorReadLine();
|
||||
Instance.BeginOutputReadLine();
|
||||
@@ -469,12 +367,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == Models.State.Started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (State == State.Started) return true;
|
||||
|
||||
if (State == Models.State.Stopped)
|
||||
if (State == State.Stopped)
|
||||
{
|
||||
Stop();
|
||||
return false;
|
||||
@@ -485,46 +380,132 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// TUN/TAP停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
public override void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
}
|
||||
StopInstance();
|
||||
ClearBypass();
|
||||
pDNSController.Stop();
|
||||
}
|
||||
|
||||
//pDNSController.Stop();
|
||||
//修复点击停止按钮后再启动,DNS服务没监听的BUG
|
||||
ClearBypass();
|
||||
pDNSController.Stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!WriteLog(e)) return;
|
||||
if (State == State.Starting)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
if (e.Data.Contains("Running"))
|
||||
State = State.Started;
|
||||
else if (e.Data.Contains("failed") || e.Data.Contains("invalid vconfig file")) State = State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
/// <summary>
|
||||
/// 搜索出口
|
||||
/// </summary>
|
||||
public static bool SearchOutbounds()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
File.AppendAllText("logging\\tun2socks.log", string.Format("{0}\r\n", e.Data.Trim()));
|
||||
Logging.Info("正在搜索出口中");
|
||||
|
||||
if (State == Models.State.Starting)
|
||||
if (Win32Native.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) == 0)
|
||||
{
|
||||
Global.Adapter.Index = pRoute.dwForwardIfIndex;
|
||||
Global.Adapter.Gateway = new IPAddress(pRoute.dwForwardNextHop);
|
||||
Logging.Info($"当前 网关 地址:{Global.Adapter.Gateway}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("GetBestRoute 搜索失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info($"搜索适配器index:{Global.Adapter.Index}");
|
||||
var AddressGot = false;
|
||||
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())
|
||||
try
|
||||
{
|
||||
if (e.Data.Contains("Running"))
|
||||
var adapterProperties = adapter.GetIPProperties();
|
||||
var p = adapterProperties.GetIPv4Properties();
|
||||
Logging.Info($"检测适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {p.Index}");
|
||||
|
||||
// 通过索引查找对应适配器的 IPv4 地址
|
||||
if (p.Index == Global.Adapter.Index)
|
||||
{
|
||||
State = Models.State.Started;
|
||||
}
|
||||
else if (e.Data.Contains("failed") || e.Data.Contains("invalid vconfig file"))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
var AdapterIPs = "";
|
||||
|
||||
foreach (var ip in adapterProperties.UnicastAddresses)
|
||||
{
|
||||
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
AddressGot = true;
|
||||
Global.Adapter.Address = ip.Address;
|
||||
Logging.Info($"当前出口 IPv4 地址:{Global.Adapter.Address}");
|
||||
break;
|
||||
}
|
||||
|
||||
AdapterIPs = $"{ip.Address} | ";
|
||||
}
|
||||
|
||||
if (!AddressGot)
|
||||
{
|
||||
if (AdapterIPs.Length > 3)
|
||||
{
|
||||
AdapterIPs = AdapterIPs.Substring(0, AdapterIPs.Length - 3);
|
||||
Logging.Info($"所有出口地址:{AdapterIPs}");
|
||||
}
|
||||
|
||||
Logging.Error("出口无 IPv4 地址,当前只支持 IPv4 地址");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!AddressGot)
|
||||
{
|
||||
Logging.Error("无法找到当前使用适配器");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 搜索 TUN/TAP 适配器的索引
|
||||
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
|
||||
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID))
|
||||
{
|
||||
Logging.Error("未找到可用 TUN/TAP 适配器");
|
||||
if (MessageBoxX.Show(i18N.Translate("TUN/TAP driver is not detected. Is it installed now?"), confirm: true) == DialogResult.OK)
|
||||
{
|
||||
Configuration.addtap();
|
||||
//给点时间,不然立马安装完毕就查找适配器可能会导致找不到适配器ID
|
||||
Thread.Sleep(1000);
|
||||
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//MessageBoxX.Show(i18N.Translate("Please install TAP-Windows and create an TUN/TAP adapter manually"));
|
||||
// return false;
|
||||
}
|
||||
|
||||
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())
|
||||
if (adapter.Id == Global.TUNTAP.ComponentID)
|
||||
{
|
||||
Global.TUNTAP.Adapter = adapter;
|
||||
Global.TUNTAP.Index = adapter.GetIPProperties().GetIPv4Properties().Index;
|
||||
|
||||
Logging.Info($"找到适配器TUN/TAP:{adapter.Id}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Logging.Error("无法找到出口");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class NFController
|
||||
{
|
||||
/// <summary>
|
||||
/// 流量变动事件
|
||||
/// </summary>
|
||||
public event BandwidthUpdateHandler OnBandwidthUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// 流量变动处理器
|
||||
/// </summary>
|
||||
/// <param name="upload">上传</param>
|
||||
/// <param name="download">下载</param>
|
||||
public delegate void BandwidthUpdateHandler(long upload, long download);
|
||||
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
// 生成驱动文件路径
|
||||
public string driverPath = string.Format("{0}\\drivers\\netfilter2.sys", Environment.SystemDirectory);
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <param name="StopServiceAndRestart">先停止驱动服务再重新启动</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode, bool StopServiceAndRestart)
|
||||
{
|
||||
if (!StopServiceAndRestart)
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting Redirector")}");
|
||||
|
||||
if (!File.Exists("bin\\Redirector.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查驱动是否存在
|
||||
if (File.Exists(driverPath))
|
||||
{
|
||||
// 生成系统版本
|
||||
var version = $"{Environment.OSVersion.Version.Major.ToString()}.{Environment.OSVersion.Version.Minor.ToString()}";
|
||||
var driverName = "";
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case "10.0":
|
||||
driverName = "Win-10.sys";
|
||||
break;
|
||||
case "6.3":
|
||||
case "6.2":
|
||||
driverName = "Win-8.sys";
|
||||
break;
|
||||
case "6.1":
|
||||
case "6.0":
|
||||
driverName = "Win-7.sys";
|
||||
break;
|
||||
default:
|
||||
Utils.Logging.Info($"不支持的系统版本:{version}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查驱动版本号
|
||||
FileVersionInfo SystemfileVerInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(driverPath);
|
||||
FileVersionInfo BinFileVerInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(string.Format("bin\\{0}", driverName));
|
||||
|
||||
if (!SystemfileVerInfo.FileVersion.Equals(BinFileVerInfo.FileVersion))
|
||||
{
|
||||
Utils.Logging.Info("开始更新驱动");
|
||||
// 需要更新驱动
|
||||
try
|
||||
{
|
||||
var service = new ServiceController("netfilter2");
|
||||
if (service.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
service.Stop();
|
||||
service.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
}
|
||||
nfapinet.NFAPI.nf_unRegisterDriver("netfilter2");
|
||||
|
||||
//删除老驱动
|
||||
File.Delete(driverPath);
|
||||
if (!InstallDriver())
|
||||
return false;
|
||||
|
||||
Utils.Logging.Info($"驱动更新完毕,当前驱动版本:{BinFileVerInfo.FileVersion}");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Utils.Logging.Info($"更新驱动出错");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!InstallDriver())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 启动驱动服务
|
||||
var service = new ServiceController("netfilter2");
|
||||
if (service.Status == ServiceControllerStatus.Running && StopServiceAndRestart)
|
||||
{
|
||||
// 防止其他程序占用 重置 NF 百万连接数限制
|
||||
service.Stop();
|
||||
service.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting netfilter2 Service")}");
|
||||
service.Start();
|
||||
}
|
||||
else if (service.Status == ServiceControllerStatus.Stopped)
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting netfilter2 Service")}");
|
||||
service.Start();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
|
||||
var result = nfapinet.NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result != nfapinet.NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Utils.Logging.Info($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var processes = "";
|
||||
foreach (var proc in mode.Rule)
|
||||
{
|
||||
processes += proc;
|
||||
processes += ",";
|
||||
}
|
||||
processes += "NTT.exe";
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\Redirector.exe";
|
||||
Instance.StartInfo.Arguments = "";
|
||||
|
||||
if (server.Type != "Socks5")
|
||||
{
|
||||
Instance.StartInfo.Arguments += $"-r 127.0.0.1:{Global.Settings.Socks5LocalPort} -p \"{processes}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Utils.DNS.Lookup(server.Hostname);
|
||||
if (result == null)
|
||||
{
|
||||
Utils.Logging.Info("无法解析服务器 IP 地址");
|
||||
return false;
|
||||
}
|
||||
|
||||
Instance.StartInfo.Arguments += $"-r {result}:{server.Port} -p \"{processes}\"";
|
||||
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -username \"{server.Username}\" -password \"{server.Password}\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists("logging\\redirector.log"))
|
||||
{
|
||||
File.Delete("logging\\redirector.log");
|
||||
}
|
||||
|
||||
Instance.StartInfo.Arguments += $" -t {Global.Settings.RedirectorTCPPort}";
|
||||
Utils.Logging.Info(Instance.StartInfo.Arguments);
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
State = Models.State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (State == Models.State.Started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Logging.Info("NF 进程启动超时");
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
public bool InstallDriver()
|
||||
{
|
||||
|
||||
Utils.Logging.Info("安装驱动中");
|
||||
// 生成系统版本
|
||||
var version = $"{Environment.OSVersion.Version.Major.ToString()}.{Environment.OSVersion.Version.Minor.ToString()}";
|
||||
|
||||
// 检查系统版本并复制对应驱动
|
||||
try
|
||||
{
|
||||
switch (version)
|
||||
{
|
||||
case "10.0":
|
||||
File.Copy("bin\\Win-10.sys", driverPath);
|
||||
Utils.Logging.Info("已复制 Win10 驱动");
|
||||
break;
|
||||
case "6.3":
|
||||
case "6.2":
|
||||
File.Copy("bin\\Win-8.sys", driverPath);
|
||||
Utils.Logging.Info("已复制 Win8 驱动");
|
||||
break;
|
||||
case "6.1":
|
||||
case "6.0":
|
||||
File.Copy("bin\\Win-7.sys", driverPath);
|
||||
Utils.Logging.Info("已复制 Win7 驱动");
|
||||
break;
|
||||
default:
|
||||
Utils.Logging.Info($"不支持的系统版本:{version}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info("复制驱动文件失败");
|
||||
Utils.Logging.Info(e.ToString());
|
||||
return false;
|
||||
}
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Register driver")}");
|
||||
// 注册驱动文件
|
||||
var result = nfapinet.NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result != nfapinet.NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Utils.Logging.Info($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
File.AppendAllText("logging\\redirector.log", string.Format("{0}\r\n", e.Data));
|
||||
|
||||
if (State == Models.State.Starting)
|
||||
{
|
||||
if (Instance.HasExited)
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
else if (e.Data.Contains("Started"))
|
||||
{
|
||||
State = Models.State.Started;
|
||||
}
|
||||
else if (e.Data.Contains("Failed") || e.Data.Contains("Unable"))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
}
|
||||
else if (State == Models.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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +1,68 @@
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class NTTController
|
||||
public class NTTController : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
private string _lastResult;
|
||||
|
||||
public NTTController()
|
||||
{
|
||||
MainFile = "NTT";
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 启动NatTypeTester
|
||||
/// 启动 NatTypeTester
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (bool, string, string, string) Start()
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
MainForm.Instance.NatTypeStatusText($"{Utils.i18N.Translate("Starting NatTester")}");
|
||||
if (!Ready) return (false, null, null, null);
|
||||
try
|
||||
{
|
||||
if (!File.Exists("bin\\NTT.exe"))
|
||||
{
|
||||
return (false, null, null, null);
|
||||
}
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\NTT.exe";
|
||||
Instance = GetProcess("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;
|
||||
State = State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
Instance.WaitForExit();
|
||||
|
||||
string[] result = File.ReadAllText("logging\\NTT.log").ToString().Split('#');
|
||||
var result = _lastResult.Split('#');
|
||||
var natType = result[0];
|
||||
var localEnd = result[1];
|
||||
var publicEnd = result[2];
|
||||
MainForm.Instance.NatTypeStatusText(natType);
|
||||
|
||||
return (true, natType, localEnd, publicEnd);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Utils.Logging.Info("NTT 进程出错");
|
||||
Logging.Error("NTT 进程出错");
|
||||
Stop();
|
||||
return (false, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
_lastResult = e.Data;
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
/// <summary>
|
||||
/// 无用
|
||||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,52 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class PrivoxyController
|
||||
public class PrivoxyController : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
public PrivoxyController()
|
||||
{
|
||||
foreach (var proc in Process.GetProcessesByName("Privoxy"))
|
||||
{
|
||||
try
|
||||
{
|
||||
proc.Kill();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 跳过
|
||||
}
|
||||
}
|
||||
MainFile = "Privoxy";
|
||||
ExtFiles = new[] {"default.conf"};
|
||||
InitCheck();
|
||||
}
|
||||
|
||||
if (!File.Exists("bin\\Privoxy.exe") || !File.Exists("bin\\default.conf"))
|
||||
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")
|
||||
.Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString())
|
||||
.Replace("_DEST_PORT_", socks5Port.ToString())
|
||||
.Replace("0.0.0.0", Global.Settings.LocalAddress);
|
||||
if (isSocks5)
|
||||
text = text.Replace("/ 127.0.0.1", $"/ {server.Hostname}");
|
||||
File.WriteAllText("data\\privoxy.conf", text);
|
||||
|
||||
Instance = GetProcess("bin\\Privoxy.exe", false);
|
||||
Instance.StartInfo.Arguments = "..\\data\\privoxy.conf";
|
||||
Instance.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
Instance.StartInfo.UseShellExecute = true;
|
||||
try
|
||||
{
|
||||
Instance.Start();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (server.Type != "Socks5")
|
||||
{
|
||||
File.WriteAllText("data\\privoxy.conf", File.ReadAllText("bin\\default.conf").Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString()).Replace("_DEST_PORT_", Global.Settings.Socks5LocalPort.ToString()).Replace("0.0.0.0", Global.Settings.LocalAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllText("data\\privoxy.conf", File.ReadAllText("bin\\default.conf").Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString()).Replace("_DEST_PORT_", server.Port.ToString()).Replace("s 0.0.0.0", $"s {Global.Settings.LocalAddress}").Replace("/ 127.0.0.1", $"/ {server.Hostname}"));
|
||||
}
|
||||
|
||||
|
||||
Instance = new Process
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
FileName = string.Format("{0}\\bin\\Privoxy.exe", Directory.GetCurrentDirectory()),
|
||||
Arguments = "..\\data\\privoxy.conf",
|
||||
WorkingDirectory = string.Format("{0}\\bin", Directory.GetCurrentDirectory()),
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
Instance.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
public override void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 跳过
|
||||
}
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class SSController
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting Shadowsocks")}");
|
||||
|
||||
File.Delete("logging\\shadowsocks.log");
|
||||
//从DLL启动Shaowsocks
|
||||
if (Global.Settings.BootShadowsocksFromDLL && (mode.Type == 0 || mode.Type == 1 || mode.Type == 2 || mode.Type == 3))
|
||||
{
|
||||
State = Models.State.Starting;
|
||||
var client = Encoding.UTF8.GetBytes($"0.0.0.0:{Global.Settings.Socks5LocalPort}");
|
||||
var remote = Encoding.UTF8.GetBytes($"{server.Hostname}:{server.Port}");
|
||||
var passwd = Encoding.UTF8.GetBytes($"{server.Password}");
|
||||
var method = Encoding.UTF8.GetBytes($"{server.EncryptMethod}");
|
||||
if (!NativeMethods.Shadowsocks.Info(client, remote, passwd, method))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
Logging.Info("DLL SS INFO 设置失败!");
|
||||
return false;
|
||||
}
|
||||
Logging.Info("DLL SS INFO 设置成功!");
|
||||
|
||||
if (!NativeMethods.Shadowsocks.Start())
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
Logging.Info("DLL SS 启动失败!");
|
||||
return false;
|
||||
}
|
||||
Logging.Info("DLL SS 启动成功!");
|
||||
State = Models.State.Started;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!File.Exists("bin\\Shadowsocks.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\Shadowsocks.exe";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(server.Plugin) && !string.IsNullOrWhiteSpace(server.PluginOption))
|
||||
{
|
||||
Instance.StartInfo.Arguments = $"-s {server.Hostname} -p {server.Port} -b {Global.Settings.LocalAddress} -l {Global.Settings.Socks5LocalPort} -m {server.EncryptMethod} -k \"{server.Password}\" -u --plugin {server.Plugin} --plugin-opts \"{server.PluginOption}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (mode.BypassChina)
|
||||
{
|
||||
Instance.StartInfo.Arguments += " --acl default.acl";
|
||||
}
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = Models.State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == Models.State.Started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (State == Models.State.Stopped)
|
||||
{
|
||||
Utils.Logging.Info("SS 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Logging.Info("SS 进程启动超时");
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Global.Settings.BootShadowsocksFromDLL)
|
||||
{
|
||||
NativeMethods.Shadowsocks.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
File.AppendAllText("logging\\shadowsocks.log", $"{e.Data}\r\n");
|
||||
|
||||
if (State == Models.State.Starting)
|
||||
{
|
||||
if (Instance.HasExited)
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
else if (e.Data.Contains("listening at"))
|
||||
{
|
||||
State = Models.State.Started;
|
||||
}
|
||||
else if (e.Data.Contains("Invalid config path") || e.Data.Contains("usage") || e.Data.Contains("plugin service exit unexpectedly"))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ec)
|
||||
{
|
||||
Logging.Info("写入Shadowsocks日志失败" + ec.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class SSRController
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting ShadowsocksR")}");
|
||||
|
||||
File.Delete("logging\\shadowsocksr.log");
|
||||
|
||||
if (!File.Exists("bin\\ShadowsocksR.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\ShadowsocksR.exe";
|
||||
Instance.StartInfo.Arguments = $"-s {server.Hostname} -p {server.Port} -k \"{server.Password}\" -m {server.EncryptMethod} -t 120";
|
||||
|
||||
if (!string.IsNullOrEmpty(server.Protocol))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -O {server.Protocol}";
|
||||
|
||||
if (!string.IsNullOrEmpty(server.ProtocolParam))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -G \"{server.ProtocolParam}\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(server.OBFS))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -o {server.OBFS}";
|
||||
|
||||
if (!string.IsNullOrEmpty(server.OBFSParam))
|
||||
{
|
||||
Instance.StartInfo.Arguments += $" -g \"{server.OBFSParam}\"";
|
||||
}
|
||||
}
|
||||
|
||||
Instance.StartInfo.Arguments += $" -b {Global.Settings.LocalAddress} -l {Global.Settings.Socks5LocalPort} -u";
|
||||
|
||||
if (mode.BypassChina)
|
||||
{
|
||||
Instance.StartInfo.Arguments += " --acl default.acl";
|
||||
}
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = Models.State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == Models.State.Started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (State == Models.State.Stopped)
|
||||
{
|
||||
Utils.Logging.Info("SSR 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Logging.Info("SSR 进程启动超时");
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
File.AppendAllText("logging\\shadowsocksr.log", $"{e.Data}\r\n");
|
||||
|
||||
if (State == Models.State.Starting)
|
||||
{
|
||||
if (Instance.HasExited)
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
else if (e.Data.Contains("listening at"))
|
||||
{
|
||||
State = Models.State.Started;
|
||||
}
|
||||
else if (e.Data.Contains("Invalid config path") || e.Data.Contains("usage"))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TrojanController
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
{
|
||||
Forms.MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting Trojan")}");
|
||||
|
||||
File.Delete("logging\\trojan.log");
|
||||
if (!File.Exists("bin\\Trojan.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
File.WriteAllText("data\\last.json", Newtonsoft.Json.JsonConvert.SerializeObject(new Models.Trojan()
|
||||
{
|
||||
local_addr = Global.Settings.LocalAddress,
|
||||
local_port = Global.Settings.Socks5LocalPort,
|
||||
remote_addr = server.Hostname,
|
||||
remote_port = server.Port,
|
||||
password = new List<string>()
|
||||
{
|
||||
server.Password
|
||||
}
|
||||
}));
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\Trojan.exe";
|
||||
Instance.StartInfo.Arguments = "-c ..\\data\\last.json";
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = Models.State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == Models.State.Started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (State == Models.State.Stopped)
|
||||
{
|
||||
Utils.Logging.Info("Trojan 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Logging.Info("Trojan 进程启动超时");
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
File.AppendAllText("logging\\trojan.log", $"{e.Data}\r\n");
|
||||
|
||||
if (State == Models.State.Starting)
|
||||
{
|
||||
if (Instance.HasExited)
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
else if (e.Data.Contains("started"))
|
||||
{
|
||||
State = Models.State.Started;
|
||||
}
|
||||
else if (e.Data.Contains("exiting"))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -17,6 +17,10 @@ namespace Netch.Controllers
|
||||
public const string Owner = @"NetchX";
|
||||
public const string Repo = @"Netch";
|
||||
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2020";
|
||||
public const string Version = @"1.4.12";
|
||||
|
||||
public string LatestVersionNumber;
|
||||
public string LatestVersionUrl;
|
||||
|
||||
@@ -24,10 +28,6 @@ namespace Netch.Controllers
|
||||
public event EventHandler NewVersionFoundFailed;
|
||||
public event EventHandler NewVersionNotFound;
|
||||
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2020";
|
||||
public const string Version = @"1.4.11";
|
||||
|
||||
public async void Check(bool notifyNoFound, bool isPreRelease)
|
||||
{
|
||||
try
|
||||
@@ -48,19 +48,13 @@ namespace Netch.Controllers
|
||||
else
|
||||
{
|
||||
LatestVersionNumber = latestRelease.tag_name;
|
||||
if (notifyNoFound)
|
||||
{
|
||||
NewVersionNotFound?.Invoke(this, new EventArgs());
|
||||
}
|
||||
if (notifyNoFound) NewVersionNotFound?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e.Message);
|
||||
if (notifyNoFound)
|
||||
{
|
||||
NewVersionFoundFailed?.Invoke(this, new EventArgs());
|
||||
}
|
||||
if (notifyNoFound) NewVersionFoundFailed?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class VMessController
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process Instance;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public Models.State State = Models.State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Models.Server server, Models.Mode mode)
|
||||
{
|
||||
MainForm.Instance.StatusText($"{Utils.i18N.Translate("Status")}{Utils.i18N.Translate(": ")}{Utils.i18N.Translate("Starting V2ray")}");
|
||||
if (!File.Exists("bin\\v2ray.exe") || !File.Exists("bin\\v2ctl.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
File.WriteAllText("data\\last.json", Newtonsoft.Json.JsonConvert.SerializeObject(new Models.Information.VMess.Config
|
||||
{
|
||||
inbounds = new List<Models.Information.VMess.Inbounds>
|
||||
{
|
||||
new Models.Information.VMess.Inbounds
|
||||
{
|
||||
settings = new Models.Information.VMess.InboundSettings(),
|
||||
port = Global.Settings.Socks5LocalPort,
|
||||
listen = Global.Settings.LocalAddress
|
||||
}
|
||||
},
|
||||
outbounds = new List<Models.Information.VMess.Outbounds>
|
||||
{
|
||||
new Models.Information.VMess.Outbounds
|
||||
{
|
||||
settings = new Models.Information.VMess.OutboundSettings
|
||||
{
|
||||
vnext = new List<Models.Information.VMess.VNext>
|
||||
{
|
||||
new Models.Information.VMess.VNext
|
||||
{
|
||||
address = server.Hostname,
|
||||
port = server.Port,
|
||||
users = new List<Models.Information.VMess.User>
|
||||
{
|
||||
new Models.Information.VMess.User
|
||||
{
|
||||
id = server.UserID,
|
||||
alterId = server.AlterID,
|
||||
security = server.EncryptMethod
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
streamSettings = new Models.Information.VMess.StreamSettings
|
||||
{
|
||||
network = server.TransferProtocol,
|
||||
security = server.TLSSecure ? "tls" : "",
|
||||
wsSettings = server.TransferProtocol == "ws" ? new Models.Information.VMess.WebSocketSettings
|
||||
{
|
||||
path = server.Path == "" ? "/" : server.Path,
|
||||
headers = new Models.Information.VMess.WSHeaders
|
||||
{
|
||||
Host = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
} : null,
|
||||
tcpSettings = server.FakeType == "http" ? new Models.Information.VMess.TCPSettings
|
||||
{
|
||||
header = new Models.Information.VMess.TCPHeaders
|
||||
{
|
||||
type = server.FakeType,
|
||||
request = new Models.Information.VMess.TCPRequest
|
||||
{
|
||||
path = server.Path == "" ? "/" : server.Path,
|
||||
headers = new Models.Information.VMess.TCPRequestHeaders
|
||||
{
|
||||
Host = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
}
|
||||
}
|
||||
} : null,
|
||||
kcpSettings = server.TransferProtocol == "kcp" ? new Models.Information.VMess.KCPSettings
|
||||
{
|
||||
header = new Models.Information.VMess.TCPHeaders
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
} : null,
|
||||
quicSettings = server.TransferProtocol == "quic" ? new Models.Information.VMess.QUICSettings
|
||||
{
|
||||
security = server.QUICSecure,
|
||||
key = server.QUICSecret,
|
||||
header = new Models.Information.VMess.TCPHeaders
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
} : null,
|
||||
httpSettings = server.TransferProtocol == "h2" ? new Models.Information.VMess.HTTPSettings
|
||||
{
|
||||
host = server.Host == "" ? server.Hostname : server.Host,
|
||||
path = server.Path == "" ? "/" : server.Path
|
||||
} : null,
|
||||
tlsSettings = new Models.Information.VMess.TLSSettings
|
||||
{
|
||||
allowInsecure = true,
|
||||
serverName = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
},
|
||||
mux = new Models.Information.VMess.OutboundMux
|
||||
{
|
||||
enabled = server.UseMux
|
||||
}
|
||||
},
|
||||
(mode.Type==0||mode.Type==1||mode.Type==2) ? new Models.Information.VMess.Outbounds
|
||||
{
|
||||
tag = "TUNTAP",
|
||||
protocol = "freedom"
|
||||
}: new Models.Information.VMess.Outbounds
|
||||
{
|
||||
tag = "direct",
|
||||
protocol = "freedom"
|
||||
}
|
||||
},
|
||||
routing = new Models.Information.VMess.Routing
|
||||
{
|
||||
rules = new List<Models.Information.VMess.RoutingRules>
|
||||
{
|
||||
mode.BypassChina ? new Models.Information.VMess.RoutingRules
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
{
|
||||
"geoip:cn",
|
||||
"geoip:private"
|
||||
|
||||
},
|
||||
domain = new List<string>
|
||||
{
|
||||
"geosite:cn"
|
||||
},
|
||||
outboundTag = "direct"
|
||||
} : new Models.Information.VMess.RoutingRules
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
{
|
||||
"geoip:private"
|
||||
},
|
||||
outboundTag = "direct"
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// 清理上一次的日志文件,防止淤积占用磁盘空间
|
||||
if (Directory.Exists("logging"))
|
||||
{
|
||||
if (File.Exists("logging\\v2ray.log"))
|
||||
{
|
||||
File.Delete("logging\\v2ray.log");
|
||||
}
|
||||
}
|
||||
|
||||
Instance = MainController.GetProcess();
|
||||
Instance.StartInfo.FileName = "bin\\v2ray.exe";
|
||||
Instance.StartInfo.Arguments = "-config ..\\data\\last.json";
|
||||
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
|
||||
State = Models.State.Starting;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (State == Models.State.Started)
|
||||
{
|
||||
if (File.Exists("data\\last.json"))
|
||||
{
|
||||
File.Delete("data\\last.json");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (State == Models.State.Stopped)
|
||||
{
|
||||
Utils.Logging.Info("V2Ray 进程启动失败");
|
||||
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Logging.Info("V2Ray 进程启动超时");
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance != null && !Instance.HasExited)
|
||||
{
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Logging.Info(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.Data))
|
||||
{
|
||||
File.AppendAllText("logging\\v2ray.log", $"{e.Data}\r\n");
|
||||
|
||||
if (State == Models.State.Starting)
|
||||
{
|
||||
if (Instance.HasExited)
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
else if (e.Data.Contains("started"))
|
||||
{
|
||||
State = Models.State.Started;
|
||||
}
|
||||
else if (e.Data.Contains("config file not readable") || e.Data.Contains("failed to"))
|
||||
{
|
||||
State = Models.State.Stopped;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -13,9 +14,9 @@ namespace Netch.Forms
|
||||
|
||||
private void AboutForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = Utils.i18N.Translate(Text);
|
||||
ChannelLabel.Text = Utils.i18N.Translate(ChannelLabel.Text);
|
||||
SponsorGroupBox.Text = Utils.i18N.Translate(SponsorGroupBox.Text);
|
||||
Text = i18N.Translate(Text);
|
||||
ChannelLabel.Text = i18N.Translate(ChannelLabel.Text);
|
||||
SponsorGroupBox.Text = i18N.Translate(SponsorGroupBox.Text);
|
||||
}
|
||||
|
||||
private void AboutForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -13,10 +14,10 @@ namespace Netch.Forms
|
||||
|
||||
private void GlobalBypassIPForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = Utils.i18N.Translate(Text);
|
||||
AddButton.Text = Utils.i18N.Translate(AddButton.Text);
|
||||
DeleteButton.Text = Utils.i18N.Translate(DeleteButton.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
Text = i18N.Translate(Text);
|
||||
AddButton.Text = i18N.Translate(AddButton.Text);
|
||||
DeleteButton.Text = i18N.Translate(DeleteButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
IPListBox.Items.AddRange(Global.Settings.BypassIPs.ToArray());
|
||||
|
||||
@@ -42,12 +43,12 @@ namespace Netch.Forms
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please enter a correct IP address"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a correct IP address"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please enter an IP"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please enter an IP"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@ namespace Netch.Forms
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please select an IP"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please select an IP"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +72,8 @@ namespace Netch.Forms
|
||||
Global.Settings.BypassIPs.Add(ip as string);
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
224
Netch/Forms/MainForm.Control.cs
Normal file
224
Netch/Forms/MainForm.Control.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class Dummy
|
||||
{
|
||||
}
|
||||
|
||||
partial class MainForm
|
||||
{
|
||||
public void ControlFun()
|
||||
{
|
||||
SaveConfigs();
|
||||
if (State == State.Waiting || State == State.Stopped)
|
||||
{
|
||||
// 服务器、模式 需选择
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ModeComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select an mode first"));
|
||||
return;
|
||||
}
|
||||
|
||||
//MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
|
||||
|
||||
UpdateStatus(State.Starting);
|
||||
|
||||
Firewall.AddNetchFwRules();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
});
|
||||
|
||||
// 如果勾选启动后最小化
|
||||
if (Global.Settings.MinimizeWhenStarted)
|
||||
{
|
||||
WindowState = FormWindowState.Minimized;
|
||||
NotifyIcon.Visible = true;
|
||||
|
||||
if (IsFirstOpened)
|
||||
{
|
||||
// 显示提示语
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name,
|
||||
i18N.Translate(
|
||||
"Netch is now minimized to the notification bar, double click this icon to restore."),
|
||||
ToolTipIcon.Info);
|
||||
|
||||
IsFirstOpened = false;
|
||||
}
|
||||
|
||||
Hide();
|
||||
}
|
||||
|
||||
if (Global.Settings.StartedTcping)
|
||||
{
|
||||
// 自动检测延迟
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (State == State.Started)
|
||||
{
|
||||
server.Test();
|
||||
// 重载服务器列表
|
||||
InitServer();
|
||||
|
||||
Thread.Sleep(Global.Settings.StartedTcping_Interval * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateStatus(State.Stopped);
|
||||
StatusText(i18N.Translate("Start failed"));
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// 停止
|
||||
UpdateStatus(State.Stopping);
|
||||
MainController.Stop();
|
||||
UpdateStatus(State.Stopped);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
TestServer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private string PortText(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 (serverType == "Socks5")
|
||||
{
|
||||
// 不可控Socks5
|
||||
if (modeType == 3 || modeType == 5)
|
||||
{
|
||||
// 可控HTTP
|
||||
text.Append(
|
||||
$"HTTP {i18N.Translate("Local Port", ": ")}{Global.Settings.HTTPLocalPort}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不可控HTTP
|
||||
text.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 可控Socks5
|
||||
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}");
|
||||
}
|
||||
}
|
||||
if (text.Length > 0)
|
||||
{
|
||||
text.Append(")");
|
||||
}
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
public void OnBandwidthUpdated(long download)
|
||||
{
|
||||
try
|
||||
{
|
||||
UsedBandwidthLabel.Text = $"{i18N.Translate("Used", ": ")}{Bandwidth.Compute(download)}";
|
||||
//UploadSpeedLabel.Text = $"↑: {Utils.Bandwidth.Compute(upload - LastUploadBandwidth)}/s";
|
||||
DownloadSpeedLabel.Text = $"↑↓: {Bandwidth.Compute(download - LastDownloadBandwidth)}/s";
|
||||
|
||||
//LastUploadBandwidth = upload;
|
||||
LastDownloadBandwidth = download;
|
||||
Refresh();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBandwidthUpdated(long upload, long download)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (upload < 1 || download < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UsedBandwidthLabel.Text =
|
||||
$"{i18N.Translate("Used",": ")}{Bandwidth.Compute(upload + download)}";
|
||||
UploadSpeedLabel.Text = $"↑: {Bandwidth.Compute(upload - LastUploadBandwidth)}/s";
|
||||
DownloadSpeedLabel.Text = $"↓: {Bandwidth.Compute(download - LastDownloadBandwidth)}/s";
|
||||
|
||||
LastUploadBandwidth = upload;
|
||||
LastDownloadBandwidth = download;
|
||||
Refresh();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上一次上传的流量
|
||||
/// </summary>
|
||||
public long LastUploadBandwidth;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次下载的流量
|
||||
/// </summary>
|
||||
public long LastDownloadBandwidth;
|
||||
}
|
||||
}
|
||||
234
Netch/Forms/MainForm.Designer.cs
generated
234
Netch/Forms/MainForm.Designer.cs
generated
@@ -42,17 +42,16 @@ namespace Netch.Forms
|
||||
this.AddTrojanServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CreateProcessModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ManageProcessModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ReloadModesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ManageSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ReloadModesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.RestartServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OpenDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CleanDNSCacheToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateACLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.updateACLWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.reinstallTapDriverToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AboutToolStripButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.VersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
@@ -67,9 +66,9 @@ namespace Netch.Forms
|
||||
this.ModeComboBox = new System.Windows.Forms.SearchComboBox();
|
||||
this.ServerComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.EditPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.EditServerPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.CopyLinkPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.DeletePictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.DeleteServerPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.SpeedPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.EditModePictureBox = new System.Windows.Forms.PictureBox();
|
||||
@@ -79,7 +78,9 @@ namespace Netch.Forms
|
||||
this.UsedBandwidthLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.DownloadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.UploadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.blankToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.NatTypeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.NatTypeStatusLightLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
|
||||
this.NotifyMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
@@ -92,9 +93,9 @@ namespace Netch.Forms
|
||||
this.ConfigurationGroupBox.SuspendLayout();
|
||||
this.configLayoutPanel.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.EditPictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.EditServerPictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.CopyLinkPictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DeletePictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DeleteServerPictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).BeginInit();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.EditModePictureBox)).BeginInit();
|
||||
@@ -183,7 +184,7 @@ namespace Netch.Forms
|
||||
//
|
||||
this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.CreateProcessModeToolStripMenuItem,
|
||||
this.ManageProcessModeToolStripMenuItem});
|
||||
this.ReloadModesToolStripMenuItem});
|
||||
this.ModeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.ModeToolStripMenuItem.Name = "ModeToolStripMenuItem";
|
||||
this.ModeToolStripMenuItem.Size = new System.Drawing.Size(55, 21);
|
||||
@@ -192,16 +193,16 @@ namespace Netch.Forms
|
||||
// CreateProcessModeToolStripMenuItem
|
||||
//
|
||||
this.CreateProcessModeToolStripMenuItem.Name = "CreateProcessModeToolStripMenuItem";
|
||||
this.CreateProcessModeToolStripMenuItem.Size = new System.Drawing.Size(212, 22);
|
||||
this.CreateProcessModeToolStripMenuItem.Size = new System.Drawing.Size(202, 22);
|
||||
this.CreateProcessModeToolStripMenuItem.Text = "Create Process Mode";
|
||||
this.CreateProcessModeToolStripMenuItem.Click += new System.EventHandler(this.CreateProcessModeToolStripButton_Click);
|
||||
//
|
||||
// ManageProcessModeToolStripMenuItem
|
||||
// ReloadModesToolStripMenuItem
|
||||
//
|
||||
this.ManageProcessModeToolStripMenuItem.Name = "ManageProcessModeToolStripMenuItem";
|
||||
this.ManageProcessModeToolStripMenuItem.Size = new System.Drawing.Size(212, 22);
|
||||
this.ManageProcessModeToolStripMenuItem.Text = "Manage Process Mode";
|
||||
this.ManageProcessModeToolStripMenuItem.Click += new System.EventHandler(this.ManageProcessModeToolStripMenuItem_Click);
|
||||
this.ReloadModesToolStripMenuItem.Name = "ReloadModesToolStripMenuItem";
|
||||
this.ReloadModesToolStripMenuItem.Size = new System.Drawing.Size(202, 22);
|
||||
this.ReloadModesToolStripMenuItem.Text = "Reload Modes";
|
||||
this.ReloadModesToolStripMenuItem.Click += new System.EventHandler(this.ReloadModesToolStripMenuItem_Click);
|
||||
//
|
||||
// SubscribeToolStripMenuItem
|
||||
//
|
||||
@@ -230,38 +231,23 @@ namespace Netch.Forms
|
||||
// OptionsToolStripMenuItem
|
||||
//
|
||||
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ReloadModesToolStripMenuItem,
|
||||
this.RestartServiceToolStripMenuItem,
|
||||
this.UninstallServiceToolStripMenuItem,
|
||||
this.OpenDirectoryToolStripMenuItem,
|
||||
this.CleanDNSCacheToolStripMenuItem,
|
||||
this.UpdateACLToolStripMenuItem,
|
||||
this.updateACLWithProxyToolStripMenuItem,
|
||||
this.UninstallServiceToolStripMenuItem,
|
||||
this.reinstallTapDriverToolStripMenuItem});
|
||||
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.OptionsToolStripMenuItem.Name = "OptionsToolStripMenuItem";
|
||||
this.OptionsToolStripMenuItem.Size = new System.Drawing.Size(66, 21);
|
||||
this.OptionsToolStripMenuItem.Text = "Options";
|
||||
//
|
||||
// ReloadModesToolStripMenuItem
|
||||
// OpenDirectoryToolStripMenuItem
|
||||
//
|
||||
this.ReloadModesToolStripMenuItem.Name = "ReloadModesToolStripMenuItem";
|
||||
this.ReloadModesToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
|
||||
this.ReloadModesToolStripMenuItem.Text = "Reload Modes";
|
||||
this.ReloadModesToolStripMenuItem.Click += new System.EventHandler(this.ReloadModesToolStripMenuItem_Click);
|
||||
//
|
||||
// RestartServiceToolStripMenuItem
|
||||
//
|
||||
this.RestartServiceToolStripMenuItem.Name = "RestartServiceToolStripMenuItem";
|
||||
this.RestartServiceToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
|
||||
this.RestartServiceToolStripMenuItem.Text = "Restart Service";
|
||||
this.RestartServiceToolStripMenuItem.Click += new System.EventHandler(this.RestartServiceToolStripMenuItem_Click);
|
||||
//
|
||||
// UninstallServiceToolStripMenuItem
|
||||
//
|
||||
this.UninstallServiceToolStripMenuItem.Name = "UninstallServiceToolStripMenuItem";
|
||||
this.UninstallServiceToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
|
||||
this.UninstallServiceToolStripMenuItem.Text = "Uninstall Service";
|
||||
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
|
||||
this.OpenDirectoryToolStripMenuItem.Name = "OpenDirectoryToolStripMenuItem";
|
||||
this.OpenDirectoryToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
|
||||
this.OpenDirectoryToolStripMenuItem.Text = "Open Directory";
|
||||
this.OpenDirectoryToolStripMenuItem.Click += new System.EventHandler(this.OpenDirectoryToolStripMenuItem_Click);
|
||||
//
|
||||
// CleanDNSCacheToolStripMenuItem
|
||||
//
|
||||
@@ -284,6 +270,13 @@ namespace Netch.Forms
|
||||
this.updateACLWithProxyToolStripMenuItem.Text = "Update ACL with proxy";
|
||||
this.updateACLWithProxyToolStripMenuItem.Click += new System.EventHandler(this.updateACLWithProxyToolStripMenuItem_Click);
|
||||
//
|
||||
// UninstallServiceToolStripMenuItem
|
||||
//
|
||||
this.UninstallServiceToolStripMenuItem.Name = "UninstallServiceToolStripMenuItem";
|
||||
this.UninstallServiceToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
|
||||
this.UninstallServiceToolStripMenuItem.Text = "Uninstall Service";
|
||||
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
|
||||
//
|
||||
// reinstallTapDriverToolStripMenuItem
|
||||
//
|
||||
this.reinstallTapDriverToolStripMenuItem.Name = "reinstallTapDriverToolStripMenuItem";
|
||||
@@ -343,7 +336,7 @@ namespace Netch.Forms
|
||||
//
|
||||
this.configLayoutPanel.ColumnCount = 3;
|
||||
this.configLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.configLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.configLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.configLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.configLayoutPanel.Controls.Add(this.ProfileLabel, 0, 2);
|
||||
this.configLayoutPanel.Controls.Add(this.ModeLabel, 0, 1);
|
||||
@@ -435,9 +428,9 @@ namespace Netch.Forms
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.EditPictureBox, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.EditServerPictureBox, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.CopyLinkPictureBox, 3, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.DeletePictureBox, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.DeleteServerPictureBox, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.SpeedPictureBox, 2, 0);
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(606, 3);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
@@ -446,16 +439,17 @@ namespace Netch.Forms
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(94, 24);
|
||||
this.tableLayoutPanel2.TabIndex = 12;
|
||||
//
|
||||
// EditPictureBox
|
||||
// EditServerPictureBox
|
||||
//
|
||||
this.EditPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.EditPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("EditPictureBox.Image")));
|
||||
this.EditPictureBox.Location = new System.Drawing.Point(3, 3);
|
||||
this.EditPictureBox.Name = "EditPictureBox";
|
||||
this.EditPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.EditPictureBox.TabIndex = 7;
|
||||
this.EditPictureBox.TabStop = false;
|
||||
this.EditPictureBox.Click += new System.EventHandler(this.EditPictureBox_Click);
|
||||
this.EditServerPictureBox.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.EditServerPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.EditServerPictureBox.Image = global::Netch.Properties.Resources.edit;
|
||||
this.EditServerPictureBox.Location = new System.Drawing.Point(3, 3);
|
||||
this.EditServerPictureBox.Name = "EditServerPictureBox";
|
||||
this.EditServerPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.EditServerPictureBox.TabIndex = 7;
|
||||
this.EditServerPictureBox.TabStop = false;
|
||||
this.EditServerPictureBox.Click += new System.EventHandler(this.EditServerPictureBox_Click);
|
||||
//
|
||||
// CopyLinkPictureBox
|
||||
//
|
||||
@@ -468,21 +462,21 @@ namespace Netch.Forms
|
||||
this.CopyLinkPictureBox.TabStop = false;
|
||||
this.CopyLinkPictureBox.Click += new System.EventHandler(this.CopyLinkPictureBox_Click);
|
||||
//
|
||||
// DeletePictureBox
|
||||
// DeleteServerPictureBox
|
||||
//
|
||||
this.DeletePictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.DeletePictureBox.Image = ((System.Drawing.Image)(resources.GetObject("DeletePictureBox.Image")));
|
||||
this.DeletePictureBox.Location = new System.Drawing.Point(26, 3);
|
||||
this.DeletePictureBox.Name = "DeletePictureBox";
|
||||
this.DeletePictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.DeletePictureBox.TabIndex = 8;
|
||||
this.DeletePictureBox.TabStop = false;
|
||||
this.DeletePictureBox.Click += new System.EventHandler(this.DeletePictureBox_Click);
|
||||
this.DeleteServerPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.DeleteServerPictureBox.Image = global::Netch.Properties.Resources.delete;
|
||||
this.DeleteServerPictureBox.Location = new System.Drawing.Point(26, 3);
|
||||
this.DeleteServerPictureBox.Name = "DeleteServerPictureBox";
|
||||
this.DeleteServerPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.DeleteServerPictureBox.TabIndex = 8;
|
||||
this.DeleteServerPictureBox.TabStop = false;
|
||||
this.DeleteServerPictureBox.Click += new System.EventHandler(this.DeleteServerPictureBox_Click);
|
||||
//
|
||||
// SpeedPictureBox
|
||||
//
|
||||
this.SpeedPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.SpeedPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("SpeedPictureBox.Image")));
|
||||
this.SpeedPictureBox.Image = global::Netch.Properties.Resources.speed;
|
||||
this.SpeedPictureBox.Location = new System.Drawing.Point(49, 3);
|
||||
this.SpeedPictureBox.Name = "SpeedPictureBox";
|
||||
this.SpeedPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
@@ -509,9 +503,7 @@ namespace Netch.Forms
|
||||
// EditModePictureBox
|
||||
//
|
||||
this.EditModePictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.EditModePictureBox.ErrorImage = global::Netch.Properties.Resources.edit;
|
||||
this.EditModePictureBox.Image = global::Netch.Properties.Resources.edit;
|
||||
this.EditModePictureBox.InitialImage = global::Netch.Properties.Resources.edit;
|
||||
this.EditModePictureBox.Location = new System.Drawing.Point(3, 3);
|
||||
this.EditModePictureBox.Name = "EditModePictureBox";
|
||||
this.EditModePictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
@@ -538,7 +530,9 @@ namespace Netch.Forms
|
||||
this.UsedBandwidthLabel,
|
||||
this.DownloadSpeedLabel,
|
||||
this.UploadSpeedLabel,
|
||||
this.NatTypeStatusLabel});
|
||||
this.blankToolStripStatusLabel,
|
||||
this.NatTypeStatusLabel,
|
||||
this.NatTypeStatusLightLabel});
|
||||
this.StatusStrip.Location = new System.Drawing.Point(0, 250);
|
||||
this.StatusStrip.Name = "StatusStrip";
|
||||
this.StatusStrip.Size = new System.Drawing.Size(733, 22);
|
||||
@@ -573,10 +567,29 @@ namespace Netch.Forms
|
||||
this.UploadSpeedLabel.Text = "↑: 0 KB/s";
|
||||
this.UploadSpeedLabel.Visible = false;
|
||||
//
|
||||
// blankToolStripStatusLabel
|
||||
//
|
||||
this.blankToolStripStatusLabel.Name = "blankToolStripStatusLabel";
|
||||
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(268, 17);
|
||||
this.blankToolStripStatusLabel.Spring = true;
|
||||
//
|
||||
// NatTypeStatusLabel
|
||||
//
|
||||
this.NatTypeStatusLabel.Name = "NatTypeStatusLabel";
|
||||
this.NatTypeStatusLabel.Size = new System.Drawing.Size(0, 17);
|
||||
this.NatTypeStatusLabel.Size = new System.Drawing.Size(36, 17);
|
||||
this.NatTypeStatusLabel.Text = "NAT:";
|
||||
this.NatTypeStatusLabel.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
|
||||
//
|
||||
// NatTypeStatusLightLabel
|
||||
//
|
||||
this.NatTypeStatusLightLabel.ActiveLinkColor = System.Drawing.Color.Red;
|
||||
this.NatTypeStatusLightLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.NatTypeStatusLightLabel.ForeColor = System.Drawing.Color.Red;
|
||||
this.NatTypeStatusLightLabel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.NatTypeStatusLightLabel.Name = "NatTypeStatusLightLabel";
|
||||
this.NatTypeStatusLightLabel.Size = new System.Drawing.Size(18, 21);
|
||||
this.NatTypeStatusLightLabel.Text = "⬤";
|
||||
this.NatTypeStatusLightLabel.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
@@ -679,15 +692,16 @@ namespace Netch.Forms
|
||||
this.Text = "Netch";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
|
||||
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||
this.VisibleChanged += new System.EventHandler(this.MainForm_VisibleChanged);
|
||||
this.MenuStrip.ResumeLayout(false);
|
||||
this.MenuStrip.PerformLayout();
|
||||
this.ConfigurationGroupBox.ResumeLayout(false);
|
||||
this.configLayoutPanel.ResumeLayout(false);
|
||||
this.configLayoutPanel.PerformLayout();
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.EditPictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.EditServerPictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.CopyLinkPictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DeletePictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DeleteServerPictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).EndInit();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.EditModePictureBox)).EndInit();
|
||||
@@ -702,63 +716,65 @@ namespace Netch.Forms
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.MenuStrip MenuStrip;
|
||||
private System.Windows.Forms.ToolStripMenuItem ServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SubscribeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripLabel VersionLabel;
|
||||
private System.Windows.Forms.GroupBox ConfigurationGroupBox;
|
||||
private System.Windows.Forms.Label ServerLabel;
|
||||
private System.Windows.Forms.Label ModeLabel;
|
||||
private System.Windows.Forms.SearchComboBox ModeComboBox;
|
||||
private System.Windows.Forms.ComboBox ServerComboBox;
|
||||
private System.Windows.Forms.StatusStrip StatusStrip;
|
||||
private System.Windows.Forms.ToolStripStatusLabel StatusLabel;
|
||||
private System.Windows.Forms.Button ControlButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddSocks5ServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddShadowsocksServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripButton AboutToolStripButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddShadowsocksRServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddShadowsocksServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddSocks5ServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddTrojanServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddVMessServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem CleanDNSCacheToolStripMenuItem;
|
||||
private System.Windows.Forms.TableLayoutPanel configLayoutPanel;
|
||||
private System.Windows.Forms.GroupBox ConfigurationGroupBox;
|
||||
private System.Windows.Forms.Button ControlButton;
|
||||
private System.Windows.Forms.PictureBox CopyLinkPictureBox;
|
||||
private System.Windows.Forms.ToolStripMenuItem CreateProcessModeToolStripMenuItem;
|
||||
private System.Windows.Forms.PictureBox DeleteModePictureBox;
|
||||
private System.Windows.Forms.PictureBox DeleteServerPictureBox;
|
||||
private System.Windows.Forms.ToolStripStatusLabel DownloadSpeedLabel;
|
||||
private System.Windows.Forms.PictureBox EditModePictureBox;
|
||||
private System.Windows.Forms.PictureBox EditServerPictureBox;
|
||||
private System.Windows.Forms.ToolStripMenuItem ExitToolStripButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ImportServersFromClipboardToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ManageSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.PictureBox SpeedPictureBox;
|
||||
private System.Windows.Forms.PictureBox DeletePictureBox;
|
||||
private System.Windows.Forms.PictureBox EditPictureBox;
|
||||
private System.Windows.Forms.ToolStripMenuItem RestartServiceToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UninstallServiceToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem OptionsToolStripMenuItem;
|
||||
private System.Windows.Forms.MenuStrip MenuStrip;
|
||||
private System.Windows.Forms.SearchComboBox ModeComboBox;
|
||||
private System.Windows.Forms.Label ModeLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem ModeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem CreateProcessModeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ReloadModesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel NatTypeStatusLabel;
|
||||
private System.Windows.Forms.NotifyIcon NotifyIcon;
|
||||
private System.Windows.Forms.ContextMenuStrip NotifyMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem ShowMainFormToolStripButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem ExitToolStripButton;
|
||||
private System.Windows.Forms.Button SettingsButton;
|
||||
private System.Windows.Forms.ToolStripButton AboutToolStripButton;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UsedBandwidthLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UploadSpeedLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel DownloadSpeedLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem CleanDNSCacheToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem OpenDirectoryToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem OptionsToolStripMenuItem;
|
||||
private System.Windows.Forms.GroupBox ProfileGroupBox;
|
||||
private System.Windows.Forms.Label ProfileLabel;
|
||||
private System.Windows.Forms.TextBox ProfileNameText;
|
||||
private System.Windows.Forms.GroupBox ProfileGroupBox;
|
||||
private System.Windows.Forms.TableLayoutPanel ProfileTable;
|
||||
private System.Windows.Forms.ToolStripMenuItem ManageProcessModeToolStripMenuItem;
|
||||
private System.Windows.Forms.PictureBox EditModePictureBox;
|
||||
private System.Windows.Forms.PictureBox DeleteModePictureBox;
|
||||
private System.Windows.Forms.PictureBox CopyLinkPictureBox;
|
||||
private System.Windows.Forms.ToolStripStatusLabel NatTypeStatusLabel;
|
||||
private System.Windows.Forms.TableLayoutPanel configLayoutPanel;
|
||||
private System.Windows.Forms.ToolStripMenuItem reinstallTapDriverToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ReloadModesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem RelyToolStripMenuItem;
|
||||
private System.Windows.Forms.ComboBox ServerComboBox;
|
||||
private System.Windows.Forms.Label ServerLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem ServerToolStripMenuItem;
|
||||
private System.Windows.Forms.Button SettingsButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem ShowMainFormToolStripButton;
|
||||
private System.Windows.Forms.PictureBox SpeedPictureBox;
|
||||
private System.Windows.Forms.ToolStripStatusLabel StatusLabel;
|
||||
private System.Windows.Forms.StatusStrip StatusStrip;
|
||||
private System.Windows.Forms.ToolStripMenuItem SubscribeToolStripMenuItem;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.ToolStripMenuItem UninstallServiceToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateACLToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem updateACLWithProxyToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem reinstallTapDriverToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddTrojanServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem RelyToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UploadSpeedLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UsedBandwidthLabel;
|
||||
private System.Windows.Forms.ToolStripLabel VersionLabel;
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStripStatusLabel NatTypeStatusLightLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel blankToolStripStatusLabel;
|
||||
}
|
||||
}
|
||||
470
Netch/Forms/MainForm.MenuStrip.cs
Normal file
470
Netch/Forms/MainForm.MenuStrip.cs
Normal file
@@ -0,0 +1,470 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Forms.Server;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using nfapinet;
|
||||
using Trojan = Netch.Forms.Server.Trojan;
|
||||
using VMess = Netch.Forms.Server.VMess;
|
||||
using WebClient = Netch.Override.WebClient;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
partial class Dummy
|
||||
{
|
||||
}
|
||||
|
||||
partial class MainForm
|
||||
{
|
||||
#region MenuStrip
|
||||
|
||||
#region 服务器
|
||||
|
||||
private void ImportServersFromClipboardToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var texts = Clipboard.GetText();
|
||||
if (!string.IsNullOrWhiteSpace(texts))
|
||||
{
|
||||
var result = ShareLink.Parse(texts);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
Global.Settings.Server.AddRange(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Import servers error!"), info: false);
|
||||
}
|
||||
|
||||
InitServer();
|
||||
Configuration.Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSocks5ServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new Socks5().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void AddShadowsocksServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new Shadowsocks().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void AddShadowsocksRServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new ShadowsocksR().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void AddVMessServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new VMess().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void AddTrojanServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new Trojan().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 模式
|
||||
|
||||
private void CreateProcessModeToolStripButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
new Process().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 订阅
|
||||
|
||||
private void ManageSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new SubscribeForm().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var bak_State = State;
|
||||
var bak_StateText = StatusLabel.Text;
|
||||
|
||||
if (Global.Settings.UseProxyToUpdateSubscription && ServerComboBox.SelectedIndex == -1)
|
||||
Global.Settings.UseProxyToUpdateSubscription = false;
|
||||
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
{
|
||||
// 当前 ServerComboBox 中至少有一项
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
|
||||
ControlButton.Text = "...";
|
||||
}
|
||||
|
||||
if (Global.Settings.SubscribeLink.Count > 0)
|
||||
{
|
||||
StatusText(i18N.Translate("Starting update subscription"));
|
||||
DeleteServerPictureBox.Enabled = false;
|
||||
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = false;
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
MainController = new MainController();
|
||||
MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
}
|
||||
|
||||
foreach (var item in Global.Settings.SubscribeLink)
|
||||
{
|
||||
using var client = new WebClient();
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.UserAgent))
|
||||
{
|
||||
client.Headers.Add("User-Agent", item.UserAgent);
|
||||
}
|
||||
else
|
||||
{
|
||||
client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36");
|
||||
}
|
||||
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
{
|
||||
client.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
|
||||
}
|
||||
|
||||
var response = client.DownloadString(item.Link);
|
||||
|
||||
try
|
||||
{
|
||||
response = ShareLink.URLSafeBase64Decode(response);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Global.Settings.Server = Global.Settings.Server.Where(server => server.Group != item.Remark).ToList();
|
||||
var result = ShareLink.Parse(response);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
foreach (var x in result)
|
||||
{
|
||||
x.Group = item.Remark;
|
||||
}
|
||||
|
||||
Global.Settings.Server.AddRange(result);
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name,
|
||||
string.Format(i18N.Translate("Update {1} server(s) from {0}"), item.Remark, result.Count),
|
||||
ToolTipIcon.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name,
|
||||
string.Format(i18N.Translate("Update servers error from {0}"), item.Remark),
|
||||
ToolTipIcon.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
InitServer();
|
||||
DeleteServerPictureBox.Enabled = true;
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
{
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
|
||||
ControlButton.Text = i18N.Translate("Start");
|
||||
MainController.Stop();
|
||||
NatTypeStatusLabel.Text = "";
|
||||
}
|
||||
|
||||
Configuration.Save();
|
||||
StatusText(i18N.Translate("Subscription updated"));
|
||||
|
||||
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,
|
||||
UpdateChecker.Name,
|
||||
i18N.Translate("Updating in the background"),
|
||||
ToolTipIcon.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("No subscription link"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#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;
|
||||
StatusText(i18N.Translate("Uninstalling Service"));
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (NFController.UninstallDriver())
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Service has been uninstalled"), owner: this);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(i18N.Translate("Error", e.Message));
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
|
||||
StatusText(i18N.Translate(StateExtension.GetStatusString(State.Waiting)));
|
||||
Enabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Enabled = false;
|
||||
SaveConfigs();
|
||||
Task.Run(() =>
|
||||
{
|
||||
InitMode();
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Modes have been reload"), owner: this);
|
||||
Enabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
private void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var bak_State = State;
|
||||
var bak_StateText = StatusLabel.Text;
|
||||
|
||||
try
|
||||
{
|
||||
Enabled = false;
|
||||
DNS.Cache.Clear();
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("DNS cache cleanup succeeded"), owner: this);
|
||||
StatusText(i18N.Translate("DNS cache cleanup succeeded"));
|
||||
Enabled = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateStatus(bak_State);
|
||||
StatusLabel.Text = bak_StateText;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Utils.Utils.OpenDir(@".\");
|
||||
}
|
||||
|
||||
private void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
StatusText(i18N.Translate("Reinstalling TUN/TAP driver"));
|
||||
Enabled = false;
|
||||
try
|
||||
{
|
||||
Configuration.deltapall();
|
||||
Configuration.addtap();
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name, i18N.Translate("Reinstall TUN/TAP driver successfully"),
|
||||
ToolTipIcon.Info);
|
||||
}
|
||||
catch
|
||||
{
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name, i18N.Translate("Reinstall TUN/TAP driver failed"),
|
||||
ToolTipIcon.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateStatus(State.Waiting);
|
||||
Enabled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateACLWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
updateACLWithProxyToolStripMenuItem.Enabled = false;
|
||||
|
||||
// 当前 ServerComboBox 中至少有一项
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
|
||||
ControlButton.Text = "...";
|
||||
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
MainController = new MainController();
|
||||
MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
|
||||
using var client = new WebClient();
|
||||
|
||||
client.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
|
||||
|
||||
StatusText(i18N.Translate("Updating in the background"));
|
||||
try
|
||||
{
|
||||
client.DownloadFile(Global.Settings.ACL, "bin\\default.acl");
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name, i18N.Translate("ACL updated successfully"),
|
||||
ToolTipIcon.Info);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("使用代理更新 ACL 失败!" + e);
|
||||
MessageBoxX.Show(i18N.Translate("ACL update failed") + "\n" + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateStatus(State.Waiting);
|
||||
MainController.Stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Exit(true);
|
||||
}
|
||||
|
||||
private void RelyToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start("https://mega.nz/file/9OQ1EazJ#0pjJ3xt57AVLr29vYEEv15GSACtXVQOGlEOPpi_2Ico");
|
||||
}
|
||||
|
||||
private void VersionLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start($"https://github.com/{UpdateChecker.Owner}/{UpdateChecker.Repo}/releases");
|
||||
}
|
||||
|
||||
private void AboutToolStripButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
new AboutForm().Show();
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void updateACLToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var bak_State = State;
|
||||
var bak_StateText = StatusLabel.Text;
|
||||
|
||||
StatusText(i18N.Translate("Starting update ACL"));
|
||||
using var client = new WebClient();
|
||||
|
||||
client.DownloadFileTaskAsync(Global.Settings.ACL, "bin\\default.acl");
|
||||
client.DownloadFileCompleted += ((sender, args) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (args.Error == null)
|
||||
{
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name, i18N.Translate("ACL updated successfully"),
|
||||
ToolTipIcon.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("ACL 更新失败!" + args.Error);
|
||||
MessageBoxX.Show(i18N.Translate("ACL update failed") + "\n" + args.Error);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateStatus(bak_State);
|
||||
StatusLabel.Text = bak_StateText;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
32
Netch/Forms/MainForm.Misc.cs
Normal file
32
Netch/Forms/MainForm.Misc.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
/// <summary lang="en">
|
||||
/// this class is used to disable Designer <para />
|
||||
/// </summary>
|
||||
/// <summary lang="zh">
|
||||
/// 此类用于禁用设计器
|
||||
/// </summary>
|
||||
[DesignerCategory("")] public partial class Dummy { }
|
||||
partial class MainForm
|
||||
{
|
||||
private void CheckUpdate()
|
||||
{
|
||||
var updater = new UpdateChecker();
|
||||
updater.NewVersionFound += (o, args) =>
|
||||
{
|
||||
NotifyIcon.ShowBalloonTip(5,
|
||||
UpdateChecker.Name,
|
||||
$"{i18N.Translate(@"New version available",": ")}{updater.LatestVersionNumber}",
|
||||
ToolTipIcon.Info);
|
||||
};
|
||||
updater.Check(false, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
206
Netch/Forms/MainForm.Profile.cs
Normal file
206
Netch/Forms/MainForm.Profile.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
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 _configurationGroupBoxHeight;
|
||||
|
||||
private void InitProfile()
|
||||
{
|
||||
foreach (var button in ProfileButtons)
|
||||
{
|
||||
button.Dispose();
|
||||
}
|
||||
|
||||
ProfileButtons.Clear();
|
||||
ProfileTable.ColumnStyles.Clear();
|
||||
ProfileTable.RowStyles.Clear();
|
||||
|
||||
var numProfile = Global.Settings.ProfileCount;
|
||||
if (numProfile == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Global.Settings.Profiles.Add(new Profile());
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
ProfileButtons.Add(b);
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
private string LoadProfile(int index)
|
||||
{
|
||||
var p = Global.Settings.Profiles[index];
|
||||
|
||||
if (p.IsDummy)
|
||||
throw new Exception("Profile not found.");
|
||||
|
||||
var result = false;
|
||||
|
||||
foreach (Models.Server server in ServerComboBox.Items)
|
||||
{
|
||||
if (server.Remark.Equals(p.ServerRemark))
|
||||
{
|
||||
ServerComboBox.SelectedItem = server;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
throw new Exception("Server not found.");
|
||||
|
||||
result = false;
|
||||
foreach (Models.Mode mode in ModeComboBox.Items)
|
||||
{
|
||||
if (mode.Remark.Equals(p.ModeRemark))
|
||||
{
|
||||
ModeComboBox.SelectedItem = mode;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
throw new Exception("Mode not found.");
|
||||
|
||||
return p.ProfileName;
|
||||
}
|
||||
|
||||
private void SaveProfile(int index)
|
||||
{
|
||||
var selectedServer = (Models.Server) ServerComboBox.SelectedItem;
|
||||
var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
var name = ProfileNameText.Text;
|
||||
|
||||
Global.Settings.Profiles[index] = new Profile(selectedServer, selectedMode, name);
|
||||
}
|
||||
|
||||
public 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)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
}
|
||||
else if (ModeComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select an mode first"));
|
||||
}
|
||||
else if (ProfileNameText.Text == "")
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a profile name first"));
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveProfile(index);
|
||||
ProfileButtons[index].Text = ProfileNameText.Text;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProfileNameText.Text = LoadProfile(index);
|
||||
|
||||
// start the profile
|
||||
var need2ndStart = true;
|
||||
if (State == State.Waiting || State == State.Stopped)
|
||||
{
|
||||
need2ndStart = false;
|
||||
}
|
||||
|
||||
ControlButton.PerformClick();
|
||||
|
||||
if (need2ndStart)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (State != State.Stopped)
|
||||
{
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
ControlButton.PerformClick();
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Logging.Info(ee.Message);
|
||||
ProfileButtons[index].Text = i18N.Translate("Error");
|
||||
Thread.Sleep(1200);
|
||||
ProfileButtons[index].Text = i18N.Translate("None");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
263
Netch/Forms/MainForm.Server_Mode.cs
Normal file
263
Netch/Forms/MainForm.Server_Mode.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class Dummy
|
||||
{
|
||||
}
|
||||
|
||||
partial class MainForm
|
||||
{
|
||||
#region Server
|
||||
|
||||
public void TestServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
Parallel.ForEach(Global.Settings.Server, new ParallelOptions {MaxDegreeOfParallelism = 16},
|
||||
server => { server.Test(); });
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void InitServer()
|
||||
{
|
||||
ServerComboBox.Items.Clear();
|
||||
ServerComboBox.Items.AddRange(Global.Settings.Server.ToArray());
|
||||
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ServerComboBoxSelectedIndex > 0 &&
|
||||
Global.Settings.ServerComboBoxSelectedIndex < ServerComboBox.Items.Count)
|
||||
{
|
||||
ServerComboBox.SelectedIndex = Global.Settings.ServerComboBoxSelectedIndex;
|
||||
}
|
||||
// 如果值非法,且当前 ServerComboBox 中有元素,选择第一个位置
|
||||
else if (ServerComboBox.Items.Count > 0)
|
||||
{
|
||||
ServerComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
// 如果当前 ServerComboBox 中没元素,不做处理
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mode
|
||||
|
||||
public void InitMode()
|
||||
{
|
||||
ModeComboBox.Items.Clear();
|
||||
Global.ModeFiles.Clear();
|
||||
|
||||
if (Directory.Exists("mode"))
|
||||
{
|
||||
foreach (var name in Directory.GetFiles("mode", "*.txt"))
|
||||
{
|
||||
var ok = true;
|
||||
var mode = new Models.Mode();
|
||||
|
||||
using (var sr = new StringReader(File.ReadAllText(name)))
|
||||
{
|
||||
var i = 0;
|
||||
string text;
|
||||
|
||||
while ((text = sr.ReadLine()) != null)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
var splited = text.Trim().Substring(1).Split(',');
|
||||
|
||||
if (splited.Length == 0)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (splited.Length >= 1)
|
||||
{
|
||||
mode.Remark = i18N.Translate(splited[0].Trim());
|
||||
}
|
||||
|
||||
if (splited.Length >= 2)
|
||||
{
|
||||
if (int.TryParse(splited[1], out var result))
|
||||
{
|
||||
mode.Type = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (splited.Length >= 3)
|
||||
{
|
||||
if (int.TryParse(splited[2], out var result))
|
||||
{
|
||||
mode.BypassChina = result == 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!text.StartsWith("#") && !string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
mode.Rule.Add(text.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
mode.FileName = Path.GetFileNameWithoutExtension(name);
|
||||
Global.ModeFiles.Add(mode);
|
||||
}
|
||||
}
|
||||
|
||||
var array = Global.ModeFiles.ToArray();
|
||||
Array.Sort(array, (a, b) => string.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
|
||||
|
||||
ModeComboBox.Items.AddRange(array);
|
||||
|
||||
SelectLastMode();
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectLastMode()
|
||||
{
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ModeComboBoxSelectedIndex > 0 &&
|
||||
Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
|
||||
{
|
||||
ModeComboBox.SelectedIndex = Global.Settings.ModeComboBoxSelectedIndex;
|
||||
}
|
||||
// 如果值非法,且当前 ModeComboBox 中有元素,选择第一个位置
|
||||
else if (ModeComboBox.Items.Count > 0)
|
||||
{
|
||||
ModeComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
// 如果当前 ModeComboBox 中没元素,不做处理
|
||||
}
|
||||
|
||||
public void AddMode(Models.Mode mode)
|
||||
{
|
||||
ModeComboBox.Items.Clear();
|
||||
Global.ModeFiles.Add(mode);
|
||||
var array = Global.ModeFiles.ToArray();
|
||||
Array.Sort(array, (a, b) => string.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
|
||||
ModeComboBox.Items.AddRange(array);
|
||||
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
public void UpdateMode(Models.Mode NewMode, Models.Mode OldMode)
|
||||
{
|
||||
ModeComboBox.Items.Clear();
|
||||
Global.ModeFiles.Remove(OldMode);
|
||||
Global.ModeFiles.Add(NewMode);
|
||||
var array = Global.ModeFiles.ToArray();
|
||||
Array.Sort(array, (a, b) => string.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
|
||||
ModeComboBox.Items.AddRange(array);
|
||||
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Init at MainForm_Load()
|
||||
/// </summary>
|
||||
private int _eWidth;
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(sender is ComboBox cbx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 绘制背景颜色
|
||||
e.Graphics.FillRectangle(new SolidBrush(Color.White), e.Bounds);
|
||||
|
||||
if (e.Index < 0) return;
|
||||
|
||||
// 绘制 备注/名称 字符串
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, new SolidBrush(Color.Black), e.Bounds);
|
||||
|
||||
switch (cbx.Items[e.Index])
|
||||
{
|
||||
case Models.Server _:
|
||||
{
|
||||
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);
|
||||
|
||||
// 绘制延迟字符串
|
||||
e.Graphics.DrawString(item.Delay.ToString(), cbx.Font, new SolidBrush(Color.Black),
|
||||
_eWidth * 9 + _eWidth / 30, e.Bounds.Y);
|
||||
break;
|
||||
}
|
||||
case Models.Mode _:
|
||||
{
|
||||
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);
|
||||
|
||||
// 绘制 模式行数 字符串
|
||||
e.Graphics.DrawString(item.Rule.Count.ToString(), cbx.Font, new SolidBrush(Color.Black),
|
||||
_eWidth * 9 + _eWidth / 30, e.Bounds.Y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
156
Netch/Forms/MainForm.Status.cs
Normal file
156
Netch/Forms/MainForm.Status.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class Dummy
|
||||
{
|
||||
}
|
||||
|
||||
partial class MainForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public State State { get; private set; } = State.Waiting;
|
||||
|
||||
public void NatTypeStatusText(string text = "",string Country = "")
|
||||
{
|
||||
if (State != State.Started)
|
||||
{
|
||||
NatTypeStatusLabel.Text = "";
|
||||
NatTypeStatusLabel.Visible = NatTypeStatusLightLabel.Visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
if (Country != "")
|
||||
{
|
||||
NatTypeStatusLabel.Text = String.Format("NAT{0}{1}[{2}]", i18N.Translate(": "), text, Country);
|
||||
}
|
||||
else
|
||||
{
|
||||
NatTypeStatusLabel.Text = String.Format("NAT{0}{1}", i18N.Translate(": "), text);
|
||||
}
|
||||
if (Enum.TryParse(text, false, out STUN_Client.NatType natType))
|
||||
{
|
||||
NatTypeStatusLightLabel.Visible = true;
|
||||
UpdateNatTypeLight(natType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NatTypeStatusLabel.Text = "NAT" + i18N.Translate(": ") + i18N.Translate("Test failed");
|
||||
}
|
||||
|
||||
NatTypeStatusLabel.Visible = true;
|
||||
}
|
||||
|
||||
private void UpdateNatTypeLight(STUN_Client.NatType natType)
|
||||
{
|
||||
Color c;
|
||||
switch (natType)
|
||||
{
|
||||
case STUN_Client.NatType.UdpBlocked:
|
||||
case STUN_Client.NatType.SymmetricUdpFirewall:
|
||||
case STUN_Client.NatType.Symmetric:
|
||||
c = Color.Red;
|
||||
break;
|
||||
case STUN_Client.NatType.RestrictedCone:
|
||||
case STUN_Client.NatType.PortRestrictedCone:
|
||||
c = Color.Yellow;
|
||||
break;
|
||||
case STUN_Client.NatType.OpenInternet:
|
||||
case STUN_Client.NatType.FullCone:
|
||||
c = Color.LimeGreen;
|
||||
break;
|
||||
default:
|
||||
c = Color.Black;
|
||||
break;
|
||||
}
|
||||
|
||||
NatTypeStatusLightLabel.ForeColor = c;
|
||||
}
|
||||
|
||||
|
||||
public void StatusText(string text)
|
||||
{
|
||||
StatusLabel.Text = i18N.Translate("Status", ": ") + text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update UI, Status, Status Label
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
public void UpdateStatus(State state)
|
||||
{
|
||||
State = state;
|
||||
StatusText(i18N.Translate(StateExtension.GetStatusString(state)));
|
||||
// TODO 补充
|
||||
switch (state)
|
||||
{
|
||||
case State.Waiting:
|
||||
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;
|
||||
|
||||
UninstallServiceToolStripMenuItem.Enabled = false;
|
||||
updateACLWithProxyToolStripMenuItem.Enabled = false;
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = false;
|
||||
reinstallTapDriverToolStripMenuItem.Enabled = false;
|
||||
break;
|
||||
case State.Started:
|
||||
ControlButton.Enabled = true;
|
||||
ControlButton.Text = i18N.Translate("Stop");
|
||||
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;
|
||||
NatTypeStatusText();
|
||||
break;
|
||||
case State.Stopped:
|
||||
ControlButton.Enabled = true;
|
||||
ControlButton.Text = i18N.Translate("Start");
|
||||
|
||||
LastUploadBandwidth = 0;
|
||||
LastDownloadBandwidth = 0;
|
||||
|
||||
ServerComboBox.Enabled = true;
|
||||
ModeComboBox.Enabled = true;
|
||||
ProfileGroupBox.Enabled = true;
|
||||
|
||||
UninstallServiceToolStripMenuItem.Enabled = true;
|
||||
updateACLWithProxyToolStripMenuItem.Enabled = true;
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = true;
|
||||
reinstallTapDriverToolStripMenuItem.Enabled = true;
|
||||
break;
|
||||
case State.Terminating:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateStatus()
|
||||
{
|
||||
UpdateStatus(State);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -120,51 +120,6 @@
|
||||
<metadata name="MenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="EditPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAg9JREFUOE+F
|
||||
U81uElEYnTdw58qFunBlYnwAE7e+QhMT38CNcefWxKWufADjiqqtmsZIW2gRulBTY4fGGGmLMFOGn5aB
|
||||
GYa5c+f4nTsINKF6kkPIxz3nO/f7Llas1IXXGyW8Wi9h+T/kmVx+C7WGA8F14S2LxR8HdfjDAMMwFI7O
|
||||
YQg/CI14pVDGKIoGYnDZomMgB4gk0VAqgUoWkxjHMd5t7eCkTz2uWIxGd601nHYPR66H+nH7LKXW9LrG
|
||||
JBrHeL+9g1N/gDRNl4wBoxHhKDJxmWierPG3lGeiaGrQ9DpPjMFADJjA7fSko4ff0nWerDntWQJegQbl
|
||||
XRsLEiweZMAEEoFn1opl9GXopa97sFaLlWmCY0nAjo2WdCYn3ednIGvHodPCSIw+2z9hrRQqZoWzBLOu
|
||||
jBvJ1MlYyARK+LGl8LCWYq+vsyvMttA17oduiwOaru4vEhGvdzSuVRUu2THu7KvJDCYJxrHKugr5XdZk
|
||||
6kSsgWJXo+pr7J5q3K7GeFoXA75EDuRfYOyCdLZFTDhhipyboDsIv2QGg6H5YREorvSyzgTFH7wEnh8g
|
||||
0frxdAbn4Vs/xYtmNguK10TcCXjF+JmUrlpvNj/lDxqu2cDZFxialb1sKly0FZYl8oZc4yRK+CYeiPie
|
||||
8IYlH3dz+W3zuub5Vv5x33/V8VwG9aimsCniMEl92dZN0SxRB+D+Hw2grtB8iuYFAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="DeletePictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAglJREFUOE+V
|
||||
k81PE1EUxUcXunEFS02MJibsZGfc6L6iazGaGI07QXcaE+PClf+ECxP/CKWwUFJqpVNKodAPGgtiW2g7
|
||||
03am89WZ47mvTdwUhJv8mua9e+7cd995GoAL5Cq5SB42jQ7S+RIWf2TwNZFWxJM6fm4U0GgZN5kzQc6T
|
||||
KXJNCpwjb/1gMJMt7GBhJY217TJqhy2YPUtRb7aRK1WkULC6WTRdz/9IzQ1yWQqcpXhqJZvHdz2nBEeF
|
||||
1Xcged/S62CROJeuSIGYfFnEfhCoxONiEIZIskgqt40oimY1nvnzQmIVHcsepfw/+p6HOI+6f9D8oMnA
|
||||
9HJ1tHXyyFf3kVjbhCbT/tM0hqtOH1G9huigPh7uwR7OqNXpceA6tC/86crgAh/u+zew79+FPXtvPNxz
|
||||
X88j6nXhOC4WU9lhgV6P5+e53FdzsO7chj0zHit2C87cE0Qd81+BeDKDettUbcFoI9wpIayUx1MusvdD
|
||||
ldruWspkmjgsW9lTi6eJwl4Ny/oGNNpTXYnNlk4anh9gicPfrTU+aVGEGO2pHDYYhKOUo4Pm4Vspqiuk
|
||||
qd6JE5/SlsqeyfWtYzuRPBEvpTJi6xdcUlaeJPOO5/liT3l5W5VdtMyu8r5g8M6Lv34roXx5JH5MrkuB
|
||||
R+QMmWB7l2jP55IkExaBIP+X+VaqtcbLMAynmftgqMOzv61mlBRRiHFjAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="SpeedPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAk9JREFUOE9N
|
||||
k19ojWEcx8+xsRgzbSlaJouGRCNuXIyMXJ1LpVyYFAttqylEsdKQC1yZpF24oJQrN0q5UJKUlP3DWTPz
|
||||
pzmm2Tk753nf9+fzfd/3nJ2nPr3v8z7P7/d7nu/v+ybMbBUsA703wwk/sKcPJz07POzszOg8HXAKBr55
|
||||
bLMmWKOgxZCEBfH7zg9/fev55Gw8G9jUXGC/IFMI7HXGt7ZBZ9fGHNtsJVQogYIrQMFVOc8GLn5x4eby
|
||||
UWB6k8AXU75N5gJ9aoBkMYGqL4JLbHB9bFRA+Xj207Pr0fcbTNtgC1QWE1TC6t/5INvF0UdmwgqlkZ4N
|
||||
rJvvP3JBmul6OArSrloJ6mAz3H383bMHE6FApZFlqitpbcbZhTnfWrzA9rNUDfVKsAFSY1Q5+9mFopWP
|
||||
IU6TGnJ2nrXetCslY6hwnRLo/q1XWVTr/iHwdCECQS2PFpl81IUnBLZ+LNit8bALRyA8gTTY0f816vVl
|
||||
Klwh2UneH5GweJ53076d5pv04SrSQiLWKkEVbFUl9VtItPYRZ6/iVr7549sx5sORuP2wBw5BgxIsgY2w
|
||||
DVZAlwLVc21/GwdTWRfvhXp4Cbv1rgRrQRbeDge466xaplO8x5FxMEvWCctBRTpgH4RGWgdyoRZuSyiJ
|
||||
qcrSIQ5+DgtBCXQCuXAphFaWjfVsnMD752iX2tQ5b6g7sAv0w20CiV50b3gCuTDB1ub7mGjvYCF0XRzc
|
||||
B/rrGkGqK7BYVI5MaFILSdzVdI9WHuRvG42Cj4Mc2g4toEJKUAMZSJlZzX8eY2N9ZDKIEQAAAABJRU5E
|
||||
rkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="StatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>122, 17</value>
|
||||
</metadata>
|
||||
@@ -174,6 +129,7 @@
|
||||
<metadata name="NotifyMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>393, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="NotifyIcon.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAMAAAAAAAEAIAAoIAQANgAAAEBAAAABACAAKEIAAF4gBAAgIAAAAQAgAKgQAACGYgQAKAAAAAAB
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
{
|
||||
public partial class Process : Form
|
||||
{
|
||||
//用于判断当前窗口是否为编辑模式
|
||||
private Boolean EditMode = false;
|
||||
private bool EditMode;
|
||||
//被编辑模式坐标
|
||||
private Models.Mode EditMode_Old = null;
|
||||
private Models.Mode EditMode_Old;
|
||||
/// <summary>
|
||||
/// 编辑模式
|
||||
/// </summary>
|
||||
@@ -23,7 +25,7 @@ namespace Netch.Forms.Mode
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
|
||||
EditMode_Old = mode;
|
||||
this.Text = "Edit Process Mode";
|
||||
Text = "Edit Process Mode";
|
||||
//循环填充已有规则
|
||||
mode.Rule.ForEach(i => RuleListBox.Items.Add(i));
|
||||
|
||||
@@ -67,7 +69,7 @@ namespace Netch.Forms.Mode
|
||||
return;
|
||||
}
|
||||
|
||||
var DirStack = new System.Collections.Generic.Stack<string>();
|
||||
var DirStack = new Stack<string>();
|
||||
DirStack.Push(DirName);
|
||||
|
||||
while (DirStack.Count > 0)
|
||||
@@ -89,16 +91,16 @@ namespace Netch.Forms.Mode
|
||||
|
||||
private void ModeForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = Utils.i18N.Translate(Text);
|
||||
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
FilenameLabel.Text = Utils.i18N.Translate(FilenameLabel.Text);
|
||||
UseCustomFilenameBox.Text = Utils.i18N.Translate(UseCustomFilenameBox.Text);
|
||||
StaySameButton.Text = Utils.i18N.Translate(StaySameButton.Text);
|
||||
TimeDataButton.Text = Utils.i18N.Translate(TimeDataButton.Text);
|
||||
AddButton.Text = Utils.i18N.Translate(AddButton.Text);
|
||||
ScanButton.Text = Utils.i18N.Translate(ScanButton.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
Text = i18N.Translate(Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
FilenameLabel.Text = i18N.Translate(FilenameLabel.Text);
|
||||
UseCustomFilenameBox.Text = i18N.Translate(UseCustomFilenameBox.Text);
|
||||
StaySameButton.Text = i18N.Translate(StaySameButton.Text);
|
||||
TimeDataButton.Text = i18N.Translate(TimeDataButton.Text);
|
||||
AddButton.Text = i18N.Translate(AddButton.Text);
|
||||
ScanButton.Text = i18N.Translate(ScanButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
if (Global.Settings.ModeFileNameType == 0)
|
||||
{
|
||||
@@ -130,12 +132,12 @@ namespace Netch.Forms.Mode
|
||||
/// </summary>
|
||||
private void RuleListBox_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
ContextMenuStrip strip = new ContextMenuStrip();
|
||||
strip.Items.Add(Utils.i18N.Translate("Delete"));
|
||||
var strip = new ContextMenuStrip();
|
||||
strip.Items.Add(i18N.Translate("Delete"));
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
strip.Show(this.RuleListBox, e.Location);//鼠标右键按下弹出菜单
|
||||
strip.MouseClick += new MouseEventHandler(deleteRule_Click);
|
||||
strip.Show(RuleListBox, e.Location);//鼠标右键按下弹出菜单
|
||||
strip.MouseClick += deleteRule_Click;
|
||||
}
|
||||
}
|
||||
void deleteRule_Click(object sender, EventArgs e)
|
||||
@@ -165,7 +167,7 @@ namespace Netch.Forms.Mode
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please enter an process name (xxx.exe)"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please enter an process name (xxx.exe)"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +177,7 @@ namespace Netch.Forms.Mode
|
||||
{
|
||||
IsFolderPicker = true,
|
||||
Multiselect = false,
|
||||
Title = Utils.i18N.Translate("Select a folder"),
|
||||
Title = i18N.Translate("Select a folder"),
|
||||
AddToMostRecentlyUsedList = false,
|
||||
EnsurePathExists = true,
|
||||
NavigateToShortcut = true
|
||||
@@ -183,7 +185,7 @@ namespace Netch.Forms.Mode
|
||||
if (dialog.ShowDialog(Win32Native.GetForegroundWindow()) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
ScanDirectory(dialog.FileName);
|
||||
MessageBox.Show(Utils.i18N.Translate("Scan completed"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Scan completed"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,14 +222,14 @@ namespace Netch.Forms.Mode
|
||||
|
||||
File.WriteAllText(Path.Combine("mode", FilenameTextBox.Text) + ".txt", text);
|
||||
|
||||
MessageBox.Show(Utils.i18N.Translate("Mode updated successfully"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
|
||||
Global.MainForm.UpdateMode(mode, EditMode_Old);
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Unable to add empty rule"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Unable to add empty rule"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -250,13 +252,13 @@ namespace Netch.Forms.Mode
|
||||
FilenameTextBox.Text = ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds).ToString();
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
Configuration.Save();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(RemarkTextBox.Text))
|
||||
{
|
||||
if (Global.Settings.ModeFileNameType == 0 && string.IsNullOrWhiteSpace(FilenameTextBox.Text))
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please enter a mode filename"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a mode filename"));
|
||||
return;
|
||||
}
|
||||
var ModeFilename = Path.Combine("mode", FilenameTextBox.Text);
|
||||
@@ -264,7 +266,7 @@ namespace Netch.Forms.Mode
|
||||
// 如果文件已存在,返回
|
||||
if (File.Exists(ModeFilename + ".txt"))
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("File already exists.\n Please Change the filename"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("File already exists.\n Please Change the filename"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -273,7 +275,7 @@ namespace Netch.Forms.Mode
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
BypassChina = false,
|
||||
FileName = ModeFilename,
|
||||
FileName = FilenameTextBox.Text,
|
||||
Type = 0,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
@@ -295,19 +297,19 @@ namespace Netch.Forms.Mode
|
||||
|
||||
File.WriteAllText(ModeFilename + ".txt", text);
|
||||
|
||||
MessageBox.Show(Utils.i18N.Translate("Mode added successfully"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
|
||||
Global.MainForm.AddMode(mode);
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Unable to add empty rule"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Unable to add empty rule"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please enter a mode remark"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a mode remark"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
@@ -22,14 +23,14 @@ namespace Netch.Forms.Server
|
||||
|
||||
private void Shadowsocks_Load(object sender, EventArgs e)
|
||||
{
|
||||
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = Utils.i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = Utils.i18N.Translate(PasswordLabel.Text);
|
||||
EncryptMethodLabel.Text = Utils.i18N.Translate(EncryptMethodLabel.Text);
|
||||
PluginLabel.Text = Utils.i18N.Translate(PluginLabel.Text);
|
||||
PluginOptionsLabel.Text = Utils.i18N.Translate(PluginOptionsLabel.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
EncryptMethodLabel.Text = i18N.Translate(EncryptMethodLabel.Text);
|
||||
PluginLabel.Text = i18N.Translate(PluginLabel.Text);
|
||||
PluginOptionsLabel.Text = i18N.Translate(PluginOptionsLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
foreach (var encrypt in Global.EncryptMethods.SS)
|
||||
{
|
||||
@@ -119,8 +120,8 @@ namespace Netch.Forms.Server
|
||||
};
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Global.MainForm.InitServer();
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
@@ -22,16 +23,16 @@ namespace Netch.Forms.Server
|
||||
|
||||
private void ShadowsocksR_Load(object sender, EventArgs e)
|
||||
{
|
||||
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = Utils.i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = Utils.i18N.Translate(PasswordLabel.Text);
|
||||
EncryptMethodLabel.Text = Utils.i18N.Translate(EncryptMethodLabel.Text);
|
||||
ProtocolLabel.Text = Utils.i18N.Translate(ProtocolLabel.Text);
|
||||
ProtocolParamLabel.Text = Utils.i18N.Translate(ProtocolParamLabel.Text);
|
||||
OBFSLabel.Text = Utils.i18N.Translate(OBFSLabel.Text);
|
||||
OBFSParamLabel.Text = Utils.i18N.Translate(OBFSParamLabel.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
EncryptMethodLabel.Text = i18N.Translate(EncryptMethodLabel.Text);
|
||||
ProtocolLabel.Text = i18N.Translate(ProtocolLabel.Text);
|
||||
ProtocolParamLabel.Text = i18N.Translate(ProtocolParamLabel.Text);
|
||||
OBFSLabel.Text = i18N.Translate(OBFSLabel.Text);
|
||||
OBFSParamLabel.Text = i18N.Translate(OBFSParamLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
foreach (var encrypt in Global.EncryptMethods.SSR)
|
||||
{
|
||||
@@ -139,8 +140,8 @@ namespace Netch.Forms.Server
|
||||
};
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Global.MainForm.InitServer();
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
@@ -22,12 +23,12 @@ namespace Netch.Forms.Server
|
||||
|
||||
private void Shadowsocks_Load(object sender, EventArgs e)
|
||||
{
|
||||
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = Utils.i18N.Translate(AddressLabel.Text);
|
||||
UsernameLabel.Text = Utils.i18N.Translate(UsernameLabel.Text);
|
||||
PasswordLabel.Text = Utils.i18N.Translate(PasswordLabel.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
UsernameLabel.Text = i18N.Translate(UsernameLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
if (Index != -1)
|
||||
{
|
||||
@@ -102,8 +103,8 @@ namespace Netch.Forms.Server
|
||||
};
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Global.MainForm.InitServer();
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
@@ -22,11 +23,11 @@ namespace Netch.Forms.Server
|
||||
|
||||
private void Trojan_Load(object sender, EventArgs e)
|
||||
{
|
||||
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = Utils.i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = Utils.i18N.Translate(PasswordLabel.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
if (Index != -1)
|
||||
{
|
||||
@@ -98,8 +99,8 @@ namespace Netch.Forms.Server
|
||||
};
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Global.MainForm.InitServer();
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
@@ -43,21 +44,21 @@ namespace Netch.Forms.Server
|
||||
|
||||
private void VMess_Load(object sender, EventArgs e)
|
||||
{
|
||||
ConfigurationGroupBox.Text = Utils.i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = Utils.i18N.Translate(AddressLabel.Text);
|
||||
UserIDLabel.Text = Utils.i18N.Translate(UserIDLabel.Text);
|
||||
AlterIDLabel.Text = Utils.i18N.Translate(AlterIDLabel.Text);
|
||||
EncryptMethodLabel.Text = Utils.i18N.Translate(EncryptMethodLabel.Text);
|
||||
TransferProtocolLabel.Text = Utils.i18N.Translate(TransferProtocolLabel.Text);
|
||||
FakeTypeLabel.Text = Utils.i18N.Translate(FakeTypeLabel.Text);
|
||||
HostLabel.Text = Utils.i18N.Translate(HostLabel.Text);
|
||||
PathLabel.Text = Utils.i18N.Translate(PathLabel.Text);
|
||||
QUICSecurityLabel.Text = Utils.i18N.Translate(QUICSecurityLabel.Text);
|
||||
QUICSecretLabel.Text = Utils.i18N.Translate(QUICSecretLabel.Text);
|
||||
TLSSecureCheckBox.Text = Utils.i18N.Translate(TLSSecureCheckBox.Text);
|
||||
UseMuxCheckBox.Text = Utils.i18N.Translate(UseMuxCheckBox.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
UserIDLabel.Text = i18N.Translate(UserIDLabel.Text);
|
||||
AlterIDLabel.Text = i18N.Translate(AlterIDLabel.Text);
|
||||
EncryptMethodLabel.Text = i18N.Translate(EncryptMethodLabel.Text);
|
||||
TransferProtocolLabel.Text = i18N.Translate(TransferProtocolLabel.Text);
|
||||
FakeTypeLabel.Text = i18N.Translate(FakeTypeLabel.Text);
|
||||
HostLabel.Text = i18N.Translate(HostLabel.Text);
|
||||
PathLabel.Text = i18N.Translate(PathLabel.Text);
|
||||
QUICSecurityLabel.Text = i18N.Translate(QUICSecurityLabel.Text);
|
||||
QUICSecretLabel.Text = i18N.Translate(QUICSecretLabel.Text);
|
||||
TLSSecureCheckBox.Text = i18N.Translate(TLSSecureCheckBox.Text);
|
||||
UseMuxCheckBox.Text = i18N.Translate(UseMuxCheckBox.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
foreach (var encrypt in Global.EncryptMethods.VMess)
|
||||
{
|
||||
@@ -118,7 +119,7 @@ namespace Netch.Forms.Server
|
||||
}
|
||||
if (AlterIDTextBox.Text == "")
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Please fill in alterID"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Please fill in alterID"));
|
||||
return;
|
||||
}
|
||||
if (Index == -1)
|
||||
@@ -165,8 +166,8 @@ namespace Netch.Forms.Server
|
||||
};
|
||||
}
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Global.MainForm.InitServer();
|
||||
Close();
|
||||
}
|
||||
|
||||
4
Netch/Forms/SettingForm.Designer.cs
generated
4
Netch/Forms/SettingForm.Designer.cs
generated
@@ -473,9 +473,9 @@
|
||||
//
|
||||
// ProfileCount_TextBox
|
||||
//
|
||||
this.ProfileCount_TextBox.Location = new System.Drawing.Point(209, 164);
|
||||
this.ProfileCount_TextBox.Location = new System.Drawing.Point(120, 164);
|
||||
this.ProfileCount_TextBox.Name = "ProfileCount_TextBox";
|
||||
this.ProfileCount_TextBox.Size = new System.Drawing.Size(226, 23);
|
||||
this.ProfileCount_TextBox.Size = new System.Drawing.Size(90, 23);
|
||||
this.ProfileCount_TextBox.TabIndex = 9;
|
||||
this.ProfileCount_TextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using Netch.Models.SSD;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
using TaskScheduler;
|
||||
|
||||
namespace Netch.Forms
|
||||
@@ -46,20 +44,20 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
private void InitText()
|
||||
{
|
||||
Text = Utils.i18N.Translate(Text);
|
||||
PortGroupBox.Text = Utils.i18N.Translate(PortGroupBox.Text);
|
||||
AllowDevicesCheckBox.Text = Utils.i18N.Translate(AllowDevicesCheckBox.Text);
|
||||
TUNTAPAddressLabel.Text = Utils.i18N.Translate(TUNTAPAddressLabel.Text);
|
||||
TUNTAPNetmaskLabel.Text = Utils.i18N.Translate(TUNTAPNetmaskLabel.Text);
|
||||
TUNTAPGatewayLabel.Text = Utils.i18N.Translate(TUNTAPGatewayLabel.Text);
|
||||
UseCustomDNSCheckBox.Text = Utils.i18N.Translate(UseCustomDNSCheckBox.Text);
|
||||
ProxyDNSCheckBox.Text = Utils.i18N.Translate(ProxyDNSCheckBox.Text);
|
||||
UseFakeDNSCheckBox.Text = Utils.i18N.Translate(UseFakeDNSCheckBox.Text);
|
||||
GlobalBypassIPsButton.Text = Utils.i18N.Translate(GlobalBypassIPsButton.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
BootShadowsocksFromDLLCheckBox.Text = Utils.i18N.Translate(BootShadowsocksFromDLLCheckBox.Text);
|
||||
Text = i18N.Translate(Text);
|
||||
PortGroupBox.Text = i18N.Translate(PortGroupBox.Text);
|
||||
AllowDevicesCheckBox.Text = i18N.Translate(AllowDevicesCheckBox.Text);
|
||||
TUNTAPAddressLabel.Text = i18N.Translate(TUNTAPAddressLabel.Text);
|
||||
TUNTAPNetmaskLabel.Text = i18N.Translate(TUNTAPNetmaskLabel.Text);
|
||||
TUNTAPGatewayLabel.Text = i18N.Translate(TUNTAPGatewayLabel.Text);
|
||||
UseCustomDNSCheckBox.Text = i18N.Translate(UseCustomDNSCheckBox.Text);
|
||||
ProxyDNSCheckBox.Text = i18N.Translate(ProxyDNSCheckBox.Text);
|
||||
UseFakeDNSCheckBox.Text = i18N.Translate(UseFakeDNSCheckBox.Text);
|
||||
GlobalBypassIPsButton.Text = i18N.Translate(GlobalBypassIPsButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
BootShadowsocksFromDLLCheckBox.Text = i18N.Translate(BootShadowsocksFromDLLCheckBox.Text);
|
||||
|
||||
ExitWhenClosedCheckBox.Checked = Global.Settings.ExitWhenClosed;
|
||||
StopWhenExitedCheckBox.Checked = Global.Settings.StopWhenExited;
|
||||
@@ -83,31 +81,36 @@ namespace Netch.Forms
|
||||
ProxyDNSCheckBox.Checked = Global.Settings.TUNTAP.ProxyDNS;
|
||||
UseFakeDNSCheckBox.Checked = Global.Settings.TUNTAP.UseFakeDNS;
|
||||
|
||||
BehaviorGroupBox.Text = Utils.i18N.Translate(BehaviorGroupBox.Text);
|
||||
ExitWhenClosedCheckBox.Text = Utils.i18N.Translate(ExitWhenClosedCheckBox.Text);
|
||||
StopWhenExitedCheckBox.Text = Utils.i18N.Translate(StopWhenExitedCheckBox.Text);
|
||||
StartWhenOpenedCheckBox.Text = Utils.i18N.Translate(StartWhenOpenedCheckBox.Text);
|
||||
MinimizeWhenStartedCheckBox.Text = Utils.i18N.Translate(MinimizeWhenStartedCheckBox.Text);
|
||||
RunAtStartup.Text = Utils.i18N.Translate(RunAtStartup.Text);
|
||||
CheckUpdateWhenOpenedCheckBox.Text = Utils.i18N.Translate(CheckUpdateWhenOpenedCheckBox.Text);
|
||||
ProfileCount_Label.Text = Utils.i18N.Translate(ProfileCount_Label.Text);
|
||||
DelayTestAfterStartup_Label.Text = Utils.i18N.Translate(DelayTestAfterStartup_Label.Text);
|
||||
EnableStartedTcping_CheckBox.Text = Utils.i18N.Translate(EnableStartedTcping_CheckBox.Text);
|
||||
DetectionInterval_Label.Text = Utils.i18N.Translate(DetectionInterval_Label.Text);
|
||||
DelayTestAfterStartup_Label.Text = Utils.i18N.Translate(DelayTestAfterStartup_Label.Text);
|
||||
STUNServerLabel.Text = Utils.i18N.Translate(STUNServerLabel.Text);
|
||||
STUNServerPortLabel.Text = Utils.i18N.Translate(STUNServerPortLabel.Text);
|
||||
BehaviorGroupBox.Text = i18N.Translate(BehaviorGroupBox.Text);
|
||||
ExitWhenClosedCheckBox.Text = i18N.Translate(ExitWhenClosedCheckBox.Text);
|
||||
StopWhenExitedCheckBox.Text = i18N.Translate(StopWhenExitedCheckBox.Text);
|
||||
StartWhenOpenedCheckBox.Text = i18N.Translate(StartWhenOpenedCheckBox.Text);
|
||||
MinimizeWhenStartedCheckBox.Text = i18N.Translate(MinimizeWhenStartedCheckBox.Text);
|
||||
RunAtStartup.Text = i18N.Translate(RunAtStartup.Text);
|
||||
CheckUpdateWhenOpenedCheckBox.Text = i18N.Translate(CheckUpdateWhenOpenedCheckBox.Text);
|
||||
ProfileCount_Label.Text = i18N.Translate(ProfileCount_Label.Text);
|
||||
DelayTestAfterStartup_Label.Text = i18N.Translate(DelayTestAfterStartup_Label.Text);
|
||||
EnableStartedTcping_CheckBox.Text = i18N.Translate(EnableStartedTcping_CheckBox.Text);
|
||||
DetectionInterval_Label.Text = i18N.Translate(DetectionInterval_Label.Text);
|
||||
DelayTestAfterStartup_Label.Text = i18N.Translate(DelayTestAfterStartup_Label.Text);
|
||||
STUNServerLabel.Text = i18N.Translate(STUNServerLabel.Text);
|
||||
STUNServerPortLabel.Text = i18N.Translate(STUNServerPortLabel.Text);
|
||||
|
||||
ProfileCount_TextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
STUN_ServerTextBox.Text = Global.Settings.STUN_Server.ToString();
|
||||
STUN_ServerTextBox.Text = Global.Settings.STUN_Server;
|
||||
STUN_ServerPortTextBox.Text = Global.Settings.STUN_Server_Port.ToString();
|
||||
|
||||
AclLabel.Text = Utils.i18N.Translate(AclLabel.Text);
|
||||
AclAddr.Text = Global.Settings.ACL.ToString();
|
||||
AclLabel.Text = i18N.Translate(AclLabel.Text);
|
||||
AclAddr.Text = Global.Settings.ACL;
|
||||
|
||||
LanguageLabel.Text = Utils.i18N.Translate(LanguageLabel.Text);
|
||||
LanguageComboBox.Items.AddRange(Utils.i18N.GetTranslateList().ToArray());
|
||||
LanguageLabel.Text = i18N.Translate(LanguageLabel.Text);
|
||||
LanguageComboBox.Items.AddRange(i18N.GetTranslateList().ToArray());
|
||||
LanguageComboBox.SelectedItem = Global.Settings.Language;
|
||||
}
|
||||
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
InitText();
|
||||
|
||||
if (Global.Settings.TUNTAP.DNS.Count > 0)
|
||||
{
|
||||
@@ -170,48 +173,11 @@ namespace Netch.Forms
|
||||
Global.Settings.BootShadowsocksFromDLL = BootShadowsocksFromDLLCheckBox.Checked;
|
||||
Global.Settings.Language = LanguageComboBox.SelectedItem.ToString();
|
||||
|
||||
// 加载系统语言
|
||||
if (Global.Settings.Language.Equals("System"))
|
||||
{
|
||||
// 得到当前线程语言代码
|
||||
var culture = CultureInfo.CurrentCulture.Name;
|
||||
|
||||
// 尝试加载内置中文语言
|
||||
if (culture == "zh-CN")
|
||||
{
|
||||
// 加载语言
|
||||
Utils.i18N.Load(Encoding.UTF8.GetString(Properties.Resources.zh_CN));
|
||||
}
|
||||
|
||||
// 从外置文件中加载语言
|
||||
if (File.Exists($"i18n\\{culture}"))
|
||||
{
|
||||
// 加载语言
|
||||
Utils.i18N.Load(File.ReadAllText($"i18n\\{culture}"));
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.Language.Equals("zh-CN"))
|
||||
{
|
||||
// 加载内置中文
|
||||
Utils.i18N.Load(Encoding.UTF8.GetString(Properties.Resources.zh_CN));
|
||||
}
|
||||
else if (Global.Settings.Language.Equals("en-US"))
|
||||
{
|
||||
// 加载内置英文
|
||||
Utils.i18N.Load(Global.Settings.Language);
|
||||
}
|
||||
else if (File.Exists($"i18n\\{Global.Settings.Language}"))
|
||||
{
|
||||
// 从外置文件中加载语言
|
||||
Utils.i18N.Load(File.ReadAllText($"i18n\\{Global.Settings.Language}"));
|
||||
}
|
||||
|
||||
// 开机自启判断
|
||||
TaskSchedulerClass scheduler = new TaskSchedulerClass();
|
||||
scheduler.Connect(null, null, null, null);
|
||||
ITaskFolder folder = scheduler.GetFolder("\\");
|
||||
bool taskIsExists = false;
|
||||
var scheduler = new TaskSchedulerClass();
|
||||
scheduler.Connect();
|
||||
var folder = scheduler.GetFolder("\\");
|
||||
var taskIsExists = false;
|
||||
try
|
||||
{
|
||||
folder.GetTask("Netch Startup");
|
||||
@@ -224,14 +190,14 @@ namespace Netch.Forms
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
|
||||
ITaskDefinition task = scheduler.NewTask(0);
|
||||
var task = scheduler.NewTask(0);
|
||||
task.RegistrationInfo.Author = "Netch";
|
||||
task.RegistrationInfo.Description = "Netch run at startup.";
|
||||
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
|
||||
|
||||
task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
|
||||
IExecAction action = (IExecAction)task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
|
||||
action.Path = System.Windows.Forms.Application.ExecutablePath;
|
||||
var action = (IExecAction)task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
|
||||
action.Path = Application.ExecutablePath;
|
||||
|
||||
|
||||
task.Settings.ExecutionTimeLimit = "PT0S";
|
||||
@@ -262,7 +228,7 @@ namespace Netch.Forms
|
||||
catch (FormatException)
|
||||
{
|
||||
Socks5PortTextBox.Text = Global.Settings.Socks5LocalPort.ToString();
|
||||
MessageBox.Show(Utils.i18N.Translate("Port value illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +249,7 @@ namespace Netch.Forms
|
||||
catch (FormatException)
|
||||
{
|
||||
HTTPPortTextBox.Text = Global.Settings.HTTPLocalPort.ToString();
|
||||
MessageBox.Show(Utils.i18N.Translate("Port value illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -304,7 +270,7 @@ namespace Netch.Forms
|
||||
catch (FormatException)
|
||||
{
|
||||
RedirectorTextBox.Text = Global.Settings.RedirectorTCPPort.ToString();
|
||||
MessageBox.Show(Utils.i18N.Translate("Port value illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -324,7 +290,7 @@ namespace Netch.Forms
|
||||
var Netmask = IPAddress.Parse(TUNTAPNetmaskTextBox.Text);
|
||||
var Gateway = IPAddress.Parse(TUNTAPGatewayTextBox.Text);
|
||||
|
||||
var DNS = new System.Collections.Generic.List<IPAddress>();
|
||||
var DNS = new List<IPAddress>();
|
||||
foreach (var ip in TUNTAPDNSTextBox.Text.Split(','))
|
||||
{
|
||||
DNS.Add(IPAddress.Parse(ip));
|
||||
@@ -332,7 +298,7 @@ namespace Netch.Forms
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("IP address format illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
|
||||
|
||||
TUNTAPAddressTextBox.Text = Global.Settings.TUNTAP.Address;
|
||||
TUNTAPNetmaskTextBox.Text = Global.Settings.TUNTAP.Netmask;
|
||||
@@ -366,7 +332,7 @@ namespace Netch.Forms
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCount_TextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBox.Show(Utils.i18N.Translate("ProfileCount value illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("ProfileCount value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -389,7 +355,7 @@ namespace Netch.Forms
|
||||
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);
|
||||
MessageBoxX.Show(i18N.Translate("STUN_ServerPort value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -411,7 +377,7 @@ namespace Netch.Forms
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCount_TextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBox.Show(Utils.i18N.Translate("Detection interval value illegal. Try again."), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Detection interval value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -432,8 +398,8 @@ namespace Netch.Forms
|
||||
Global.Settings.TUNTAP.ProxyDNS = ProxyDNSCheckBox.Checked;
|
||||
Global.Settings.TUNTAP.UseFakeDNS = UseFakeDNSCheckBox.Checked;
|
||||
|
||||
Utils.Configuration.Save();
|
||||
MessageBox.Show(Utils.i18N.Translate("Saved. Modify some settings need to restart the software"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -38,16 +38,16 @@ namespace Netch.Forms
|
||||
|
||||
private void SubscribeForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = Utils.i18N.Translate(Text);
|
||||
RemarkColumnHeader.Text = Utils.i18N.Translate(RemarkColumnHeader.Text);
|
||||
LinkColumnHeader.Text = Utils.i18N.Translate(LinkColumnHeader.Text);
|
||||
UseSelectedServerCheckBox.Text = Utils.i18N.Translate(UseSelectedServerCheckBox.Text);
|
||||
DeleteToolStripMenuItem.Text = Utils.i18N.Translate(DeleteToolStripMenuItem.Text);
|
||||
CopyLinkToolStripMenuItem.Text = Utils.i18N.Translate(CopyLinkToolStripMenuItem.Text);
|
||||
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
|
||||
LinkLabel.Text = Utils.i18N.Translate(LinkLabel.Text);
|
||||
AddButton.Text = Utils.i18N.Translate(AddButton.Text);
|
||||
ControlButton.Text = Utils.i18N.Translate(ControlButton.Text);
|
||||
Text = i18N.Translate(Text);
|
||||
RemarkColumnHeader.Text = i18N.Translate(RemarkColumnHeader.Text);
|
||||
LinkColumnHeader.Text = i18N.Translate(LinkColumnHeader.Text);
|
||||
UseSelectedServerCheckBox.Text = i18N.Translate(UseSelectedServerCheckBox.Text);
|
||||
DeleteToolStripMenuItem.Text = i18N.Translate(DeleteToolStripMenuItem.Text);
|
||||
CopyLinkToolStripMenuItem.Text = i18N.Translate(CopyLinkToolStripMenuItem.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
LinkLabel.Text = i18N.Translate(LinkLabel.Text);
|
||||
AddButton.Text = i18N.Translate(AddButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
UserAgentTextBox.Text = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36";
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Netch.Forms
|
||||
}
|
||||
private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MessageBox.Show(Utils.i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), Utils.i18N.Translate("Information"), MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
|
||||
if (MessageBoxX.Show(i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), confirm: true) == DialogResult.OK)
|
||||
{
|
||||
if (SubscribeLinkListView.SelectedItems.Count > 0)
|
||||
{
|
||||
@@ -128,14 +128,14 @@ namespace Netch.Forms
|
||||
{
|
||||
//是否为新增订阅
|
||||
var saveFlag = true;
|
||||
Global.Settings.SubscribeLink.ForEach((subitem) =>
|
||||
Global.Settings.SubscribeLink.ForEach(subitem =>
|
||||
{
|
||||
if (subitem.Link.Equals(LinkTextBox.Text))
|
||||
{
|
||||
if (!subitem.Remark.Equals(RemarkTextBox.Text))
|
||||
{
|
||||
//修改了订阅备注,修改旧订阅服务器
|
||||
Global.Settings.Server.ForEach((serverItem) =>
|
||||
Global.Settings.Server.ForEach(serverItem =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -159,16 +159,14 @@ namespace Netch.Forms
|
||||
subitem.UserAgent = UserAgentTextBox.Text;
|
||||
saveFlag = false;
|
||||
|
||||
Utils.Configuration.Save();
|
||||
Configuration.Save();
|
||||
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
|
||||
MessageBox.Show(Utils.i18N.Translate("Successfully saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
return;
|
||||
MessageBoxX.Show(i18N.Translate("Successfully saved"));
|
||||
}
|
||||
});
|
||||
if (saveFlag)
|
||||
{
|
||||
Global.Settings.SubscribeLink.Add(new Models.SubscribeLink
|
||||
Global.Settings.SubscribeLink.Add(new SubscribeLink
|
||||
{
|
||||
Remark = RemarkTextBox.Text,
|
||||
Link = LinkTextBox.Text,
|
||||
@@ -184,25 +182,25 @@ namespace Netch.Forms
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Links must start with http:// or https://"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Links must start with http:// or https://"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Link can not be empty"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Link can not be empty"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Utils.i18N.Translate("Remark can not be empty"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Remark can not be empty"));
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Utils.Configuration.Save();
|
||||
Configuration.Save();
|
||||
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
|
||||
MessageBox.Show(Utils.i18N.Translate("Successfully saved"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Successfully saved"));
|
||||
Close();
|
||||
}
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
@@ -6,6 +7,14 @@ namespace Netch
|
||||
{
|
||||
public static class Global
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 换行
|
||||
/// </summary>
|
||||
public static string EOF = "\r\n";
|
||||
|
||||
public static readonly string NetchDir = (AppDomain.CurrentDomain.BaseDirectory).TrimEnd();
|
||||
|
||||
/// <summary>
|
||||
/// 主窗体
|
||||
/// </summary>
|
||||
|
||||
16
Netch/Models/STUN.Client.cs
Normal file
16
Netch/Models/STUN.Client.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class STUN_Client
|
||||
{
|
||||
public enum NatType
|
||||
{
|
||||
UdpBlocked,
|
||||
OpenInternet,
|
||||
SymmetricUdpFirewall,
|
||||
FullCone,
|
||||
RestrictedCone,
|
||||
PortRestrictedCone,
|
||||
Symmetric
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,32 +156,7 @@ namespace Netch.Models
|
||||
|
||||
if (Country == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var databaseReader = new DatabaseReader("bin\\GeoLite2-Country.mmdb");
|
||||
|
||||
if (IPAddress.TryParse(Hostname, out _) == true)
|
||||
{
|
||||
Country = databaseReader.Country(Hostname).Country.IsoCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
var DnsResult = DNS.Lookup(Hostname);
|
||||
|
||||
if (DnsResult != null)
|
||||
{
|
||||
Country = databaseReader.Country(DnsResult).Country.IsoCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
Country = "UN";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Country = "UN";
|
||||
}
|
||||
Country = Utils.Utils.GetCityCode(Hostname);
|
||||
}
|
||||
|
||||
Group = Group.Equals("None") || Group.Equals("") ? "NONE" : Group;
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 已保存的快捷配置
|
||||
/// </summary>
|
||||
public List<Profile> profiles = new List<Profile>();
|
||||
public List<Profile> Profiles = new List<Profile>();
|
||||
|
||||
/// <summary>
|
||||
/// 快捷配置数量
|
||||
|
||||
@@ -36,4 +36,14 @@
|
||||
/// </summary>
|
||||
Terminating
|
||||
}
|
||||
}
|
||||
|
||||
public static class StateExtension
|
||||
{
|
||||
public static string GetStatusString(State state)
|
||||
{
|
||||
if (state == State.Waiting)
|
||||
return "Waiting for command";
|
||||
return state.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ namespace Netch.Models
|
||||
public string cert;
|
||||
public string cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
|
||||
public string cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384";
|
||||
public string sni;
|
||||
public string sni = string.Empty;
|
||||
public List<string> alpn = new List<string>()
|
||||
{
|
||||
"h2",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -24,14 +24,14 @@ namespace Netch
|
||||
// 清理上一次的日志文件,防止淤积占用磁盘空间
|
||||
if (Directory.Exists("logging"))
|
||||
{
|
||||
DirectoryInfo directory = new DirectoryInfo("logging");
|
||||
var directory = new DirectoryInfo("logging");
|
||||
|
||||
foreach (FileInfo file in directory.GetFiles())
|
||||
foreach (var file in directory.GetFiles())
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
|
||||
foreach (DirectoryInfo dir in directory.GetDirectories())
|
||||
foreach (var dir in directory.GetDirectories())
|
||||
{
|
||||
dir.Delete(true);
|
||||
}
|
||||
@@ -50,53 +50,19 @@ namespace Netch
|
||||
}
|
||||
|
||||
// 加载配置
|
||||
Utils.Configuration.Load();
|
||||
Configuration.Load();
|
||||
|
||||
// 加载系统语言
|
||||
if (Global.Settings.Language.Equals("System"))
|
||||
{
|
||||
// 得到当前线程语言代码
|
||||
var culture = CultureInfo.CurrentCulture.Name;
|
||||
|
||||
// 尝试加载内置中文语言
|
||||
if (culture == "zh-CN")
|
||||
{
|
||||
// 加载语言
|
||||
Utils.i18N.Load(Encoding.UTF8.GetString(Properties.Resources.zh_CN));
|
||||
}
|
||||
|
||||
// 从外置文件中加载语言
|
||||
if (File.Exists($"i18n\\{culture}"))
|
||||
{
|
||||
// 加载语言
|
||||
Utils.i18N.Load(File.ReadAllText($"i18n\\{culture}"));
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.Language.Equals("zh-CN"))
|
||||
{
|
||||
// 加载内置中文
|
||||
Utils.i18N.Load(Encoding.UTF8.GetString(Properties.Resources.zh_CN));
|
||||
}
|
||||
else if (Global.Settings.Language.Equals("en-US"))
|
||||
{
|
||||
// 加载内置英文
|
||||
Utils.i18N.Load(Global.Settings.Language);
|
||||
}
|
||||
else if (File.Exists($"i18n\\{Global.Settings.Language}"))
|
||||
{
|
||||
// 从外置文件中加载语言
|
||||
Utils.i18N.Load(File.ReadAllText($"i18n\\{Global.Settings.Language}"));
|
||||
}
|
||||
// 加载语言
|
||||
i18N.Load(Global.Settings.Language);
|
||||
|
||||
// 记录当前系统语言
|
||||
Utils.Logging.Info($"当前语言:{Global.Settings.Language}");
|
||||
Logging.Info($"当前语言:{Global.Settings.Language}");
|
||||
|
||||
// 检查是否已经运行
|
||||
if (!mutex.WaitOne(0, false))
|
||||
{
|
||||
// 弹出提示
|
||||
MessageBox.Show(Utils.i18N.Translate("Netch is already running"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show(i18N.Translate("Netch is already running"));
|
||||
|
||||
// 退出进程
|
||||
Environment.Exit(1);
|
||||
@@ -110,7 +76,7 @@ namespace Netch
|
||||
{
|
||||
|
||||
// 弹出提示
|
||||
MessageBox.Show($"{Utils.i18N.Translate("Netch is not compatible with your system.")}\n{Utils.i18N.Translate("Current arch of Netch:")} {PROC}\n{Utils.i18N.Translate("Current arch of system:")} {OS}", Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
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);
|
||||
@@ -122,7 +88,7 @@ namespace Netch
|
||||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(Global.MainForm = new Forms.MainForm());
|
||||
Application.Run(Global.MainForm = new MainForm());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,14 @@
|
||||
<Isolated>false</Isolated>
|
||||
<EmbedInteropTypes>false</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="NetFwTypeLib.dll">
|
||||
<Guid>58fbcf7c-e7a9-467c-80b3-fc65e8fcca08</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>false</Isolated>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{
|
||||
protected override void OnRenderToolStripBorder(System.Windows.Forms.ToolStripRenderEventArgs e)
|
||||
{
|
||||
// 跳过
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,13 @@
|
||||
"Started": "已启动",
|
||||
"Stopping": "正在停止中",
|
||||
"Stopped": "已停止",
|
||||
"Starting Shadowsocks": "正在启动 Shadowsocks",
|
||||
"Starting ShadowsocksR": "正在启动 ShadowsocksR",
|
||||
"Starting V2ray": "正在启动 V2Ray",
|
||||
"Starting Trojan": "正在启动 Trojan",
|
||||
"Starting ": "正在启动 ",
|
||||
"v2ray": "V2Ray",
|
||||
"Starting Tap": "正在启动 TUN/TAP",
|
||||
"Starting NatTester": "正在启动 NAT 测试",
|
||||
"Starting LocalDns service": "正在启动本地 DNS 服务",
|
||||
"Starting Redirector": "正在启动 Redirector",
|
||||
"ReStarting Redirector": "正常启动失败,正在尝试重新启动 Redirector",
|
||||
"Restarting Redirector": "正常启动失败,正在尝试重新启动 Redirector",
|
||||
"Starting netfilter2 Service": "正在启动 netfilter2 服务",
|
||||
"Starting dns Service": "正在启动 DNS 服务",
|
||||
"SetupBypass": "设置绕行规则",
|
||||
@@ -47,7 +45,6 @@
|
||||
"New version available": "发现新版本",
|
||||
"Mode": "模式",
|
||||
"Create Process Mode": "创建进程模式",
|
||||
"Manage Process Mode": "管理进程模式",
|
||||
"Edit Process Mode": "修改进程模式",
|
||||
|
||||
"Address": "地址",
|
||||
@@ -99,6 +96,7 @@
|
||||
"Reinstall TUN/TAP driver successfully": "重装 TUN/TAP 驱动成功",
|
||||
"Reinstall TUN/TAP driver failed": "重装 TUN/TAP 驱动失败",
|
||||
"Reinstalling TUN/TAP driver": "正在重装 TUN/TAP 驱动",
|
||||
"Open Directory": "打开目录",
|
||||
|
||||
"About": "关于",
|
||||
"Telegram Channel": "Telegram 频道",
|
||||
@@ -165,7 +163,7 @@
|
||||
"Port value illegal. Try again.": "端口值非法。请重试。",
|
||||
"Check update when opened": "打开软件时检查更新",
|
||||
"Start Shadowsocks from DLL (No support for ACL)": "SS DLL(推荐使用,不支持 ACL)",
|
||||
"ProfileCount": "快捷配置数量(重启软件生效)",
|
||||
"ProfileCount": "快捷配置数量",
|
||||
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",
|
||||
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试。",
|
||||
"Detection interval value illegal. Try again.": "检测间隔值非法。请重试。",
|
||||
@@ -179,7 +177,7 @@
|
||||
"STUN Server Port": "STUN 服务器端口",
|
||||
"Custom ACL": "自定义 ACL 规则",
|
||||
"Language": "语言",
|
||||
"Saved. Modify some settings need to restart the software": "保存成功,修改部分设置需重启软件",
|
||||
"Saved.": "保存成功",
|
||||
|
||||
"Profile": "配置名",
|
||||
"Profiles": "配置",
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
using Microsoft.Diagnostics.Tracing.Parsers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Diagnostics.Tracing.Parsers;
|
||||
using Microsoft.Diagnostics.Tracing.Session;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Bandwidth
|
||||
{
|
||||
public static int received = 0;
|
||||
public static int received;
|
||||
|
||||
/// <summary>
|
||||
/// 计算流量
|
||||
/// </summary>
|
||||
/// <param name="bandwidth">流量</param>
|
||||
/// <returns>带单位的流量字符串</returns>
|
||||
public static string Compute(long bandwidth)
|
||||
/// 计算流量
|
||||
/// </summary>
|
||||
/// <param name="bandwidth">流量</param>
|
||||
/// <returns>带单位的流量字符串</returns>
|
||||
public static string Compute(long bandwidth)
|
||||
{
|
||||
string[] units = { "KB", "MB", "GB", "TB", "PB" };
|
||||
string[] units = {"KB", "MB", "GB", "TB", "PB"};
|
||||
double result = bandwidth;
|
||||
var i = -1;
|
||||
|
||||
@@ -36,53 +35,39 @@ namespace Netch.Utils
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return string.Format("{0} {1}", System.Math.Round(result, 2), units[i]);
|
||||
return string.Format("{0} {1}", Math.Round(result, 2), units[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据程序名统计流量
|
||||
/// </summary>
|
||||
/// <param name="ProcessName"></param>
|
||||
public static void NetTraffic(Models.Server server, Models.Mode mode, MainController mainController)
|
||||
public static void NetTraffic(Server server, Mode mode, MainController mainController)
|
||||
{
|
||||
var counterLock = new object();
|
||||
//int sent = 0;
|
||||
|
||||
//var processList = Process.GetProcessesByName(ProcessName).Select(p => p.Id).ToHashSet();
|
||||
List<int> processList = new List<int>();
|
||||
var processList = new List<int>();
|
||||
|
||||
if (server.Type.Equals("Socks5") && mainController.pHTTPController != null)
|
||||
if (server.Type.Equals("Socks5") && mainController.pModeController.AkaName == "HTTP")
|
||||
{
|
||||
processList.Add(mainController.pHTTPController.pPrivoxyController.Instance.Id);
|
||||
processList.Add(((HTTPController) mainController.pModeController).pPrivoxyController.Instance.Id);
|
||||
}
|
||||
else if (server.Type.Equals("SS") && Global.Settings.BootShadowsocksFromDLL)
|
||||
{
|
||||
processList.Add(Process.GetCurrentProcess().Id);
|
||||
}
|
||||
else if (server.Type.Equals("SS") && mainController.pSSController != null)
|
||||
else if (mainController.pEncryptedProxyController != null)
|
||||
{
|
||||
processList.Add(mainController.pSSController.Instance.Id);
|
||||
// mainController.pServerClientController.Instance
|
||||
processList.Add(mainController.pEncryptedProxyController.Instance.Id);
|
||||
}
|
||||
else if (server.Type.Equals("SSR") && mainController.pSSRController != null)
|
||||
else if (mainController.pModeController != null)
|
||||
{
|
||||
processList.Add(mainController.pSSRController.Instance.Id);
|
||||
}
|
||||
else if (server.Type.Equals("VMess") && mainController.pVMessController != null)
|
||||
{
|
||||
processList.Add(mainController.pVMessController.Instance.Id);
|
||||
}
|
||||
else if (server.Type.Equals("TR") && mainController.pTrojanController != null)
|
||||
{
|
||||
processList.Add(mainController.pTrojanController.Instance.Id);
|
||||
}
|
||||
else if (mainController.pTUNTAPController != null)
|
||||
{
|
||||
processList.Add(mainController.pTUNTAPController.Instance.Id);
|
||||
}
|
||||
else if (mainController.pNFController != null)
|
||||
{
|
||||
processList.Add(mainController.pNFController.Instance.Id);
|
||||
processList.Add(mainController.pModeController.Instance.Id);
|
||||
}
|
||||
|
||||
Logging.Info("启动流量统计 PID:" + string.Join(",", processList.ToArray()));
|
||||
|
||||
Task.Run(() =>
|
||||
@@ -121,7 +106,8 @@ namespace Netch.Utils
|
||||
MainForm.Instance.OnBandwidthUpdated(0);
|
||||
received = 0;
|
||||
}
|
||||
while (MainForm.Instance.State != Models.State.Stopped)
|
||||
|
||||
while (MainForm.Instance.State != State.Stopped)
|
||||
{
|
||||
Task.Delay(1000).Wait();
|
||||
lock (counterLock)
|
||||
@@ -129,7 +115,6 @@ namespace Netch.Utils
|
||||
MainForm.Instance.OnBandwidthUpdated(Convert.ToInt64(received));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -30,13 +32,13 @@ namespace Netch.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
Global.Settings = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Setting>(File.ReadAllText(SETTINGS_JSON));
|
||||
Global.Settings = JsonConvert.DeserializeObject<Setting>(File.ReadAllText(SETTINGS_JSON));
|
||||
if (Global.Settings.Server != null && Global.Settings.Server.Count > 0)
|
||||
{
|
||||
// 如果是旧版 Server 类,使用旧版 Server 类进行读取
|
||||
if (Global.Settings.Server[0].Hostname == null)
|
||||
{
|
||||
var LegacySettingConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.LegacySetting>(File.ReadAllText(SETTINGS_JSON));
|
||||
var LegacySettingConfig = JsonConvert.DeserializeObject<LegacySetting>(File.ReadAllText(SETTINGS_JSON));
|
||||
for (var i = 0; i < LegacySettingConfig.Server.Count; i++)
|
||||
{
|
||||
Global.Settings.Server[i].Hostname = LegacySettingConfig.Server[i].Address;
|
||||
@@ -59,7 +61,7 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
catch (Newtonsoft.Json.JsonException)
|
||||
catch (JsonException)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -67,7 +69,7 @@ namespace Netch.Utils
|
||||
else
|
||||
{
|
||||
// 弹出提示
|
||||
MessageBox.Show("如果你是第一次使用本软件\n请务必前往http://netch.org 安装程序所需依赖,\n否则程序将无法正常运行!", i18N.Translate("注意!"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBoxX.Show("如果你是第一次使用本软件\n请务必前往http://netch.org 安装程序所需依赖,\n否则程序将无法正常运行!", i18N.Translate("注意!"));
|
||||
|
||||
// 创建 data 文件夹并保存默认设置
|
||||
Save();
|
||||
@@ -84,115 +86,9 @@ namespace Netch.Utils
|
||||
{
|
||||
Directory.CreateDirectory(DATA_DIR);
|
||||
}
|
||||
File.WriteAllText(SETTINGS_JSON, Newtonsoft.Json.JsonConvert.SerializeObject(Global.Settings, Newtonsoft.Json.Formatting.Indented));
|
||||
File.WriteAllText(SETTINGS_JSON, JsonConvert.SerializeObject(Global.Settings, Formatting.Indented));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索出口
|
||||
/// </summary>
|
||||
public static bool SearchOutbounds()
|
||||
{
|
||||
Logging.Info("正在搜索出口中");
|
||||
|
||||
if (Win32Native.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) == 0)
|
||||
{
|
||||
Global.Adapter.Index = pRoute.dwForwardIfIndex;
|
||||
Global.Adapter.Gateway = new IPAddress(pRoute.dwForwardNextHop);
|
||||
Logging.Info($"当前 网关 地址:{Global.Adapter.Gateway}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Info("GetBestRoute 搜索失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info($"搜索适配器index:{Global.Adapter.Index}");
|
||||
var AddressGot = false;
|
||||
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
try
|
||||
{
|
||||
var adapterProperties = adapter.GetIPProperties();
|
||||
var p = adapterProperties.GetIPv4Properties();
|
||||
Logging.Info($"检测适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {p.Index}");
|
||||
|
||||
// 通过索引查找对应适配器的 IPv4 地址
|
||||
if (p.Index == Global.Adapter.Index)
|
||||
{
|
||||
var AdapterIPs = "";
|
||||
|
||||
foreach (var ip in adapterProperties.UnicastAddresses)
|
||||
{
|
||||
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
AddressGot = true;
|
||||
Global.Adapter.Address = ip.Address;
|
||||
Logging.Info($"当前出口 IPv4 地址:{Global.Adapter.Address}");
|
||||
break;
|
||||
}
|
||||
AdapterIPs = $"{ip.Address} | ";
|
||||
}
|
||||
|
||||
if (!AddressGot)
|
||||
{
|
||||
if (AdapterIPs.Length > 3)
|
||||
{
|
||||
AdapterIPs = AdapterIPs.Substring(0, AdapterIPs.Length - 3);
|
||||
Logging.Info($"所有出口地址:{AdapterIPs}");
|
||||
}
|
||||
Logging.Info("出口无 IPv4 地址,当前只支持 IPv4 地址");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
}
|
||||
|
||||
if (!AddressGot)
|
||||
{
|
||||
Logging.Info("无法找到当前使用适配器");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 搜索 TUN/TAP 适配器的索引
|
||||
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
|
||||
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID))
|
||||
{
|
||||
Logging.Info("未找到可用 TUN/TAP 适配器");
|
||||
if (MessageBox.Show(i18N.Translate("TUN/TAP driver is not detected. Is it installed now?"), i18N.Translate("Information"), MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
|
||||
{
|
||||
addtap();
|
||||
//给点时间,不然立马安装完毕就查找适配器可能会导致找不到适配器ID
|
||||
Thread.Sleep(1000);
|
||||
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//MessageBox.Show(i18N.Translate("Please install TAP-Windows and create an TUN/TAP adapter manually"), i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
// return false;
|
||||
}
|
||||
|
||||
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
if (adapter.Id == Global.TUNTAP.ComponentID)
|
||||
{
|
||||
Global.TUNTAP.Adapter = adapter;
|
||||
Global.TUNTAP.Index = adapter.GetIPProperties().GetIPv4Properties().Index;
|
||||
|
||||
Logging.Info($"找到适配器:{adapter.Id}");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Info("无法找到出口");
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// 安装tap网卡
|
||||
/// </summary>
|
||||
@@ -200,7 +96,7 @@ namespace Netch.Utils
|
||||
{
|
||||
Logging.Info("正在安装 TUN/TAP 适配器");
|
||||
//安装Tap Driver
|
||||
Process installProcess = new Process();
|
||||
var installProcess = new Process();
|
||||
installProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
installProcess.StartInfo.FileName = Path.Combine("bin/tap-driver", "addtap.bat");
|
||||
installProcess.Start();
|
||||
@@ -213,7 +109,7 @@ namespace Netch.Utils
|
||||
public static void deltapall()
|
||||
{
|
||||
Logging.Info("正在卸载 TUN/TAP 适配器");
|
||||
Process installProcess = new Process();
|
||||
var installProcess = new Process();
|
||||
installProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
installProcess.StartInfo.FileName = Path.Combine("bin/tap-driver", "deltapall.bat");
|
||||
installProcess.Start();
|
||||
|
||||
137
Netch/Utils/Firewall.cs
Normal file
137
Netch/Utils/Firewall.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using NetFwTypeLib;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public class Firewall
|
||||
{
|
||||
private static readonly string[] ProgramPath =
|
||||
{
|
||||
"bin/NTT.exe",
|
||||
"bin/Privoxy.exe",
|
||||
"bin/Redirector.exe",
|
||||
"bin/Shadowsocks.exe",
|
||||
"bin/ShadowsocksR.exe",
|
||||
"bin/Trojan.exe",
|
||||
"bin/tun2socks.exe",
|
||||
"bin/unbound.exe",
|
||||
"bin/v2ray.exe",
|
||||
"Netch.exe"
|
||||
};
|
||||
|
||||
private const string Netch = "Netch";
|
||||
private const string NetchAutoRule = "NetchAutoRule";
|
||||
|
||||
/// <summary>
|
||||
/// 添加防火墙规则 (非 Netch 自带程序)
|
||||
/// </summary>
|
||||
/// <param name="exeFullPath"></param>
|
||||
public static void AddFwRule(string exeFullPath)
|
||||
{
|
||||
AddFwRule(NetchAutoRule, exeFullPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除防火墙规则 (非 Netch 自带程序)
|
||||
/// </summary>
|
||||
public static void RemoveFwRules()
|
||||
{
|
||||
RemoveFwRules(NetchAutoRule);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Netch 自带程序添加防火墙
|
||||
/// </summary>
|
||||
public static void AddNetchFwRules()
|
||||
{
|
||||
if (GetFwRulePath(Netch).StartsWith(Global.NetchDir) && GetFwRulesNumber(Netch) >= ProgramPath.Length) return;
|
||||
RemoveNetchFwRules();
|
||||
foreach (var p in ProgramPath)
|
||||
{
|
||||
var path = Path.GetFullPath(p);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
AddFwRule("Netch", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除防火墙规则 (Netch 自带程序)
|
||||
/// </summary>
|
||||
private static void RemoveNetchFwRules()
|
||||
{
|
||||
RemoveFwRules(Netch);
|
||||
}
|
||||
|
||||
#region 封装
|
||||
|
||||
private static readonly INetFwPolicy2 FwPolicy = (INetFwPolicy2) Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
|
||||
|
||||
private static void AddFwRule(string ruleName, string exeFullPath)
|
||||
{
|
||||
var rule = NewFwRule();
|
||||
|
||||
rule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
|
||||
// ApplicationName 大小不敏感
|
||||
rule.ApplicationName = exeFullPath;
|
||||
// rule.Description = "Used to block all internet access.";
|
||||
rule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
|
||||
rule.Enabled = true;
|
||||
rule.InterfaceTypes = "All";
|
||||
rule.Name = ruleName;
|
||||
|
||||
FwPolicy.Rules.Add(rule);
|
||||
}
|
||||
|
||||
private static void RemoveFwRules(string ruleName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = GetFwRulesNumber(ruleName);
|
||||
foreach (var _ in new bool[c])
|
||||
{
|
||||
FwPolicy.Rules.Remove(ruleName);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Info("Netch 自带程序添加防火墙出错(如已关闭防火墙则可无视此错误)\n" + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static INetFwRule NewFwRule()
|
||||
{
|
||||
return (INetFwRule) Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
|
||||
}
|
||||
|
||||
|
||||
private static string GetFwRulePath(string ruleName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rule = (INetFwRule2)FwPolicy.Rules.Item(ruleName);
|
||||
return rule.ApplicationName;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,6 @@ namespace Netch.Utils
|
||||
{
|
||||
public static class Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// 换行
|
||||
/// </summary>
|
||||
public static string EOF = "\r\n";
|
||||
|
||||
/// <summary>
|
||||
/// 信息
|
||||
@@ -16,7 +12,16 @@ namespace Netch.Utils
|
||||
/// <param name="text">内容</param>
|
||||
public static void Info(string text)
|
||||
{
|
||||
File.AppendAllText("logging\\application.log", string.Format("[{0}] {1}{2}", DateTime.Now, text, EOF));
|
||||
File.AppendAllText("logging\\application.log", $@"[{DateTime.Now}][INFO] {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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
Netch/Utils/MessageBoxX.cs
Normal file
24
Netch/Utils/MessageBoxX.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
class MessageBoxX
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="text">内容</param>
|
||||
/// <param name="title">自定义标题</param>
|
||||
/// <param name="info">弹窗等级 (标题, 图标)</param>
|
||||
/// <param name="confirm">需要确认</param>
|
||||
/// <param name="owner">阻止 owner Focus() 直到 Messageox 被关闭</param>
|
||||
public static DialogResult Show(string text, string title = "", bool info = true, bool confirm = false,IWin32Window owner = null)
|
||||
{
|
||||
return MessageBox.Show(
|
||||
owner: owner,
|
||||
text: i18N.Translate(text: text),
|
||||
caption: i18N.Translate(string.IsNullOrWhiteSpace(title) ? (info ? "Information" : "Error") : title),
|
||||
buttons: confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK,
|
||||
icon: info ? MessageBoxIcon.Information : MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
using Netch.Models;
|
||||
using Netch.Models.SS;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Models;
|
||||
using Netch.Models.SS;
|
||||
using Netch.Models.SSD;
|
||||
using Newtonsoft.Json;
|
||||
using Server = Netch.Models.Server;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -36,9 +38,9 @@ namespace Netch.Utils
|
||||
/// </summary>
|
||||
/// <param name="server">需要获取分享链接的服务器</param>
|
||||
/// <returns>解码后的字符串</returns>
|
||||
public static string GetShareLink(Models.Server server)
|
||||
public static string GetShareLink(Server server)
|
||||
{
|
||||
string retLinkStr = "";
|
||||
var retLinkStr = "";
|
||||
switch (server.Type)
|
||||
{
|
||||
case "Socks5":
|
||||
@@ -54,12 +56,12 @@ namespace Netch.Utils
|
||||
case "SSR":
|
||||
// https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
|
||||
// ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
||||
string paraStr = string.Format("/?obfsparam={0}&protoparam={1}&remarks={2}", URLSafeBase64Encode(server.OBFSParam), URLSafeBase64Encode(server.ProtocolParam), URLSafeBase64Encode(server.Remark));
|
||||
var paraStr = string.Format("/?obfsparam={0}&protoparam={1}&remarks={2}", URLSafeBase64Encode(server.OBFSParam), URLSafeBase64Encode(server.ProtocolParam), URLSafeBase64Encode(server.Remark));
|
||||
retLinkStr = "ssr://" + URLSafeBase64Encode(string.Format("{0}:{1}:{2}:{3}:{4}:{5}{6}", server.Hostname, server.Port, server.Protocol, server.EncryptMethod, server.OBFS, URLSafeBase64Encode(server.Password), paraStr));
|
||||
|
||||
break;
|
||||
case "VMess":
|
||||
string vmessJson = Newtonsoft.Json.JsonConvert.SerializeObject(new
|
||||
var vmessJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
v = "2",
|
||||
ps = server.Remark,
|
||||
@@ -121,7 +123,7 @@ namespace Netch.Utils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Info(e.ToString());
|
||||
Logging.Error(e.ToString());
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -254,7 +256,7 @@ namespace Netch.Utils
|
||||
|
||||
if (!Global.EncryptMethods.SS.Contains(data.EncryptMethod))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 SS 加密方式:{0}", data.EncryptMethod));
|
||||
Logging.Error($"不支持的 SS 加密方式:{data.EncryptMethod}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -267,7 +269,7 @@ namespace Netch.Utils
|
||||
}
|
||||
else if (text.StartsWith("ssd://"))
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<Models.SSD.Main>(URLSafeBase64Decode(text.Substring(6)));
|
||||
var json = JsonConvert.DeserializeObject<Main>(URLSafeBase64Decode(text.Substring(6)));
|
||||
|
||||
foreach (var server in json.servers)
|
||||
{
|
||||
@@ -293,85 +295,6 @@ namespace Netch.Utils
|
||||
|
||||
list.Add(SsrServerFromLink(text));
|
||||
|
||||
/* var data = new Server();
|
||||
data.Type = "SSR";
|
||||
|
||||
text = text.Substring(6);
|
||||
|
||||
var parser = new Regex(@"^(?<server>.+):(?<port>(-?\d+?)):(?<protocol>.+?):(?<method>.+?):(?<obfs>.+?):(?<password>.+?)/\?(?<info>.*)$");
|
||||
var parser2 = new Regex(@"^(?<server>.+):(?<port>(-?\d+?)):(?<protocol>.+?):(?<method>.+?):(?<obfs>.+?):(?<password>.+?)/$");
|
||||
var match = parser2.Match(URLSafeBase64Decode(text));
|
||||
if (!match.Success)
|
||||
{
|
||||
match = parser2.Match(UnBase64String(text));
|
||||
}
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
if (data.Port < 0)
|
||||
{
|
||||
data.Port += 65536;
|
||||
}
|
||||
data.Password = URLSafeBase64Decode(match.Groups["password"].Value);
|
||||
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
if (!Global.EncryptMethods.SSR.Contains(data.EncryptMethod))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 SSR 加密方式:{0}", data.EncryptMethod));
|
||||
return null;
|
||||
}
|
||||
|
||||
data.Protocol = match.Groups["protocol"].Value;
|
||||
if (!Global.Protocols.Contains(data.Protocol))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 SSR 协议:{0}", data.Protocol));
|
||||
return null;
|
||||
}
|
||||
|
||||
data.OBFS = match.Groups["obfs"].Value;
|
||||
if (data.OBFS == @"tls1.2_ticket_fastauth")
|
||||
{
|
||||
data.OBFS = @"tls1.2_ticket_auth";
|
||||
}
|
||||
if (!Global.OBFSs.Contains(data.OBFS))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 SSR 混淆:{0}", data.OBFS));
|
||||
return null;
|
||||
}
|
||||
|
||||
var info = match.Groups["info"].Value;
|
||||
var dict = new Dictionary<string, string>();
|
||||
foreach (var str in info.Split('&'))
|
||||
{
|
||||
var splited = str.Split('=');
|
||||
dict.Add(splited[0], splited[1]);
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("remarks"))
|
||||
{
|
||||
data.Remark = URLSafeBase64Decode(dict["remarks"]);
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("protoparam"))
|
||||
{
|
||||
data.ProtocolParam = URLSafeBase64Decode(dict["protoparam"]);
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("obfsparam"))
|
||||
{
|
||||
data.OBFSParam = URLSafeBase64Decode(dict["obfsparam"]);
|
||||
}
|
||||
|
||||
if (Global.EncryptMethods.SS.Contains(data.EncryptMethod) && data.Protocol == "origin" && data.OBFS == "plain")
|
||||
{
|
||||
data.OBFS = "";
|
||||
data.Type = "SS";
|
||||
}
|
||||
list.Add(data);
|
||||
}*/
|
||||
|
||||
}
|
||||
else if (text.StartsWith("vmess://"))
|
||||
{
|
||||
@@ -390,14 +313,14 @@ namespace Netch.Utils
|
||||
data.TransferProtocol = vmess.net;
|
||||
if (!Global.TransferProtocols.Contains(data.TransferProtocol))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 VMess 传输协议:{0}", data.TransferProtocol));
|
||||
Logging.Error($"不支持的 VMess 传输协议:{data.TransferProtocol}");
|
||||
return null;
|
||||
}
|
||||
|
||||
data.FakeType = vmess.type;
|
||||
if (data.FakeType.Length != 0 && !Global.FakeTypes.Contains(data.FakeType))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 VMess 伪装类型:{0}", data.FakeType));
|
||||
Logging.Error($"不支持的 VMess 伪装类型:{data.FakeType}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -414,7 +337,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (!Global.EncryptMethods.VMessQUIC.Contains(vmess.host))
|
||||
{
|
||||
Logging.Info(string.Format("不支持的 VMess QUIC 加密方式:{0}", vmess.host));
|
||||
Logging.Error($"不支持的 VMess QUIC 加密方式:{vmess.host}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -470,43 +393,43 @@ namespace Netch.Utils
|
||||
case "SS":
|
||||
if (!Global.EncryptMethods.SS.Contains(NetchLink.EncryptMethod))
|
||||
{
|
||||
Logging.Info($"不支持的 SS 加密方式:{NetchLink.EncryptMethod}");
|
||||
Logging.Error($"不支持的 SS 加密方式:{NetchLink.EncryptMethod}");
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "SSR":
|
||||
if (!Global.EncryptMethods.SSR.Contains(NetchLink.EncryptMethod))
|
||||
{
|
||||
Logging.Info($"不支持的 SSR 加密方式:{NetchLink.EncryptMethod}");
|
||||
Logging.Error($"不支持的 SSR 加密方式:{NetchLink.EncryptMethod}");
|
||||
return null;
|
||||
}
|
||||
if (!Global.Protocols.Contains(NetchLink.Protocol))
|
||||
{
|
||||
Logging.Info($"不支持的 SSR 协议:{NetchLink.Protocol}");
|
||||
Logging.Error($"不支持的 SSR 协议:{NetchLink.Protocol}");
|
||||
return null;
|
||||
}
|
||||
if (!Global.OBFSs.Contains(NetchLink.OBFS))
|
||||
{
|
||||
Logging.Info($"不支持的 SSR 混淆:{NetchLink.OBFS}");
|
||||
Logging.Error($"不支持的 SSR 混淆:{NetchLink.OBFS}");
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "VMess":
|
||||
if (!Global.TransferProtocols.Contains(NetchLink.TransferProtocol))
|
||||
{
|
||||
Logging.Info($"不支持的 VMess 传输协议:{NetchLink.TransferProtocol}");
|
||||
Logging.Error($"不支持的 VMess 传输协议:{NetchLink.TransferProtocol}");
|
||||
return null;
|
||||
}
|
||||
if (!Global.FakeTypes.Contains(NetchLink.FakeType))
|
||||
{
|
||||
Logging.Info($"不支持的 VMess 伪装类型:{NetchLink.FakeType}");
|
||||
Logging.Error($"不支持的 VMess 伪装类型:{NetchLink.FakeType}");
|
||||
return null;
|
||||
}
|
||||
if (NetchLink.TransferProtocol == "quic")
|
||||
{
|
||||
if (!Global.EncryptMethods.VMessQUIC.Contains(NetchLink.QUICSecure))
|
||||
{
|
||||
Logging.Info($"不支持的 VMess QUIC 加密方式:{NetchLink.QUICSecure}");
|
||||
Logging.Error($"不支持的 VMess QUIC 加密方式:{NetchLink.QUICSecure}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -569,15 +492,15 @@ namespace Netch.Utils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Info(e.ToString());
|
||||
Logging.Error(e.ToString());
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] emoji_bytes = { 240, 159 };
|
||||
foreach (Server node in list)
|
||||
foreach (var node in list)
|
||||
{
|
||||
var remark = Encoding.UTF8.GetBytes(node.Remark);
|
||||
int start_index = 0;
|
||||
var start_index = 0;
|
||||
while (remark.Length > start_index + 1 && remark[start_index] == emoji_bytes[0] && remark[start_index + 1] == emoji_bytes[1])
|
||||
start_index += 4;
|
||||
node.Remark = Encoding.UTF8.GetString(remark.Skip(start_index).ToArray()).Trim();
|
||||
@@ -591,7 +514,7 @@ namespace Netch.Utils
|
||||
{
|
||||
return "";
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(value);
|
||||
var bytes = Convert.FromBase64String(value);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
public static string ToBase64String(string value)
|
||||
@@ -600,7 +523,7 @@ namespace Netch.Utils
|
||||
{
|
||||
return "";
|
||||
}
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(value);
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
@@ -673,7 +596,7 @@ namespace Netch.Utils
|
||||
{
|
||||
Server_Udp_Port = ushort.Parse(params_dict["udpport"]);
|
||||
}*/
|
||||
Server server = new Server();
|
||||
var server = new Server();
|
||||
server.Type = "SSR";
|
||||
server.Hostname = serverAddr;
|
||||
server.Port = Server_Port;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using MaxMind.GeoIP2;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
@@ -64,5 +65,41 @@ namespace Netch.Utils
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public static string GetCityCode(string Hostname)
|
||||
{
|
||||
if (Hostname.Contains(":"))
|
||||
{
|
||||
Hostname = Hostname.Split(':')[0];
|
||||
}
|
||||
string Country;
|
||||
try
|
||||
{
|
||||
var databaseReader = new DatabaseReader("bin\\GeoLite2-Country.mmdb");
|
||||
|
||||
if (IPAddress.TryParse(Hostname, out _) == true)
|
||||
{
|
||||
Country = databaseReader.Country(Hostname).Country.IsoCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
var DnsResult = DNS.Lookup(Hostname);
|
||||
|
||||
if (DnsResult != null)
|
||||
{
|
||||
Country = databaseReader.Country(Hostname).Country.IsoCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
Country = "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Country = "Unknown";
|
||||
}
|
||||
return Country == null ? "Unknown" : Country;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,66 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class i18N
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 数据
|
||||
/// </summary>
|
||||
public static Hashtable Data = new Hashtable();
|
||||
|
||||
public static string LangCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 加载
|
||||
/// </summary>
|
||||
/// <param name="text">语言文件</param>
|
||||
public static void Load(string text)
|
||||
/// <param name="langCode">语言代码</param>
|
||||
public static void Load(string langCode)
|
||||
{
|
||||
if (text.Equals("en-US"))
|
||||
LangCode = langCode;
|
||||
|
||||
var text = "";
|
||||
if (langCode.Equals("System"))
|
||||
{
|
||||
// 加载系统语言
|
||||
langCode = CultureInfo.CurrentCulture.Name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (langCode == "zh-CN")
|
||||
{
|
||||
// 尝试加载内置中文语言
|
||||
text = Encoding.UTF8.GetString(Resources.zh_CN);
|
||||
}
|
||||
else if (langCode.Equals("en-US"))
|
||||
{
|
||||
// 清除得到英文
|
||||
Data.Clear();
|
||||
return;
|
||||
}
|
||||
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
|
||||
|
||||
if (data != null)
|
||||
else if (File.Exists($"i18n\\{langCode}"))
|
||||
{
|
||||
Data = new Hashtable();
|
||||
foreach (var v in data)
|
||||
{
|
||||
Data.Add(v.Key, v.Value);
|
||||
}
|
||||
// 从外置文件中加载语言
|
||||
text = File.ReadAllText($"i18n\\{langCode}");
|
||||
}
|
||||
|
||||
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
Data = new Hashtable();
|
||||
foreach (var v in data)
|
||||
{
|
||||
Data.Add(v.Key, v.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,33 +71,23 @@ namespace Netch.Utils
|
||||
/// <returns>翻译完毕的文本</returns>
|
||||
public static string Translate(string text)
|
||||
{
|
||||
if (Data.Contains(text))
|
||||
{
|
||||
return Data[text].ToString();
|
||||
}
|
||||
|
||||
return text;
|
||||
return Data.Contains(text) ? Data[text].ToString() : text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取可使用的语言
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string Translate(params string[] text)
|
||||
{
|
||||
var a = new StringBuilder();
|
||||
foreach (var t in text)
|
||||
a.Append(Data.Contains(t) ? Data[t].ToString() : t);
|
||||
return a.ToString();
|
||||
}
|
||||
|
||||
public static List<string> GetTranslateList()
|
||||
{
|
||||
List<string> TranslateFile = new List<string>();
|
||||
TranslateFile.Add("System");
|
||||
TranslateFile.Add("zh-CN");
|
||||
TranslateFile.Add("en-US");
|
||||
var translateFile = new List<string> {"System", "zh-CN", "en-US"};
|
||||
|
||||
if (Directory.Exists("i18n"))
|
||||
{
|
||||
foreach (var fileName in Directory.GetFiles("i18n", "*"))
|
||||
{
|
||||
TranslateFile.Add(fileName.Substring(5));
|
||||
}
|
||||
}
|
||||
return TranslateFile;
|
||||
if (!Directory.Exists("i18n")) return translateFile;
|
||||
translateFile.AddRange(Directory.GetFiles("i18n", "*").Select(fileName => fileName.Substring(5)));
|
||||
return translateFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,7 +281,7 @@ namespace Netch
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 跳过
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
2
binaries
2
binaries
Submodule binaries updated: f93cebfb75...841b75af2f
Submodule translations updated: db0c5ae291...e7c5263f75
Reference in New Issue
Block a user