Compare commits
66 Commits
1.8.0
...
1.8.3-Beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
947bf2b3ca | ||
|
|
2a165c79df | ||
|
|
55280df299 | ||
|
|
af48e7119e | ||
|
|
a1b978a22c | ||
|
|
d08a9d5bfd | ||
|
|
c69c40750a | ||
|
|
77376502b7 | ||
|
|
fdfc3f11eb | ||
|
|
0d956efac6 | ||
|
|
3f9709167d | ||
|
|
425e468f78 | ||
|
|
a485a4647c | ||
|
|
0b484face4 | ||
|
|
e0b5b0e49c | ||
|
|
f519850ffc | ||
|
|
4513a68e73 | ||
|
|
95de42e778 | ||
|
|
18168c3a4e | ||
|
|
77f2b761fc | ||
|
|
9bd02ec122 | ||
|
|
cfb4a5b3f6 | ||
|
|
6178045f15 | ||
|
|
4773de99e5 | ||
|
|
eb713db867 | ||
|
|
15f4895c0f | ||
|
|
afbda60dfb | ||
|
|
f51229f2c8 | ||
|
|
26f9ae3958 | ||
|
|
dfc680f0b7 | ||
|
|
5e56556534 | ||
|
|
33a0d9e7c2 | ||
|
|
939d600be1 | ||
|
|
a1e511915e | ||
|
|
94796110d5 | ||
|
|
5c3e2ab207 | ||
|
|
e66eb9759a | ||
|
|
b27ccfab17 | ||
|
|
87b3867095 | ||
|
|
3d1538264a | ||
|
|
0bffbbfb62 | ||
|
|
6ccbcae31f | ||
|
|
5a9d6e145d | ||
|
|
1b7eb6f6de | ||
|
|
62bfa25870 | ||
|
|
a1d481ba05 | ||
|
|
39abcb7d79 | ||
|
|
7c1df3786e | ||
|
|
fe11ee56ba | ||
|
|
4f38de4ee9 | ||
|
|
1aa32eaf3a | ||
|
|
4b3d6fb3bf | ||
|
|
12559d8192 | ||
|
|
bd71452206 | ||
|
|
10ba299f4d | ||
|
|
1ff9d1ec9d | ||
|
|
9cbb88c886 | ||
|
|
7e65ae0b6b | ||
|
|
41491f8c20 | ||
|
|
84b412bc8c | ||
|
|
7fef3dfe5c | ||
|
|
c139a82bdf | ||
|
|
97f6d601fb | ||
|
|
1ea0bb4096 | ||
|
|
7265bd2922 | ||
|
|
f316e13ada |
3
.github/dependabot.yml
vendored
@@ -26,8 +26,7 @@ updates:
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
interval: "daily"
|
||||
time: "07:15"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
|
||||
30
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Netch CI
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
dependabot/**
|
||||
pull_request:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Build Solution
|
||||
shell: pwsh
|
||||
run: .\BUILD.ps1
|
||||
|
||||
- name: Upload Artifact
|
||||
continue-on-error: true
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: Netch\bin\x64\Release
|
||||
@@ -1,5 +1,8 @@
|
||||
name: Netch CI
|
||||
on: [push, pull_request]
|
||||
name: Netch Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*'
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
@@ -17,14 +20,6 @@ jobs:
|
||||
shell: pwsh
|
||||
run: .\BUILD.ps1
|
||||
|
||||
- name: Upload Artifact
|
||||
continue-on-error: true
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: Netch\bin\x64\Release
|
||||
|
||||
- name: Package
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
shell: pwsh
|
||||
@@ -39,10 +34,8 @@ jobs:
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
with:
|
||||
name: ${{ env.GITHUB_TAG_NAME }}
|
||||
prerelease: true
|
||||
prerelease: ${{ contains(github.ref, '-') }}
|
||||
draft: false
|
||||
files: |
|
||||
C:\builtfiles\Netch.7z
|
||||
@@ -55,4 +48,4 @@ jobs:
|
||||
## 校验和
|
||||
| 文件名 | SHA256 |
|
||||
| :- | :- |
|
||||
| Netch.7z | ${{ env.Netch_SHA256 }} |
|
||||
| Netch.7z | ${{ env.Netch_SHA256 }} |
|
||||
7
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/.vs
|
||||
/packages
|
||||
.vs/
|
||||
.idea/
|
||||
/*.user
|
||||
*/bin/
|
||||
*/obj/
|
||||
*.csproj.user
|
||||
3
Netch/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
/bin
|
||||
/obj
|
||||
/Netch.csproj.user
|
||||
@@ -166,6 +166,7 @@ namespace Netch.Controllers
|
||||
return;
|
||||
case State.Stopped:
|
||||
Stop();
|
||||
CloseLogFile();
|
||||
OnKeywordStopped();
|
||||
throw new MessageException($"{Name} 控制器启动失败");
|
||||
}
|
||||
@@ -180,6 +181,9 @@ namespace Netch.Controllers
|
||||
|
||||
private void OpenLogFile()
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
_logStreamWriter = new StreamWriter(_logFileStream);
|
||||
|
||||
@@ -201,8 +205,8 @@ namespace Netch.Controllers
|
||||
return;
|
||||
|
||||
_flushFileStreamTimer.Enabled = false;
|
||||
_logStreamWriter!.Close();
|
||||
_logFileStream!.Close();
|
||||
_logStreamWriter?.Close();
|
||||
_logFileStream?.Close();
|
||||
_logStreamWriter = _logStreamWriter = null;
|
||||
}
|
||||
|
||||
@@ -234,8 +238,8 @@ namespace Netch.Controllers
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
OnReadNewLine(line);
|
||||
WriteLog(line);
|
||||
OnReadNewLine(line);
|
||||
|
||||
// State == State.Started if !StartedKeywords.Any()
|
||||
if (State == State.Starting)
|
||||
@@ -247,8 +251,8 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
State = State.Stopped;
|
||||
CloseLogFile();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace Netch.Controllers
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
PrivoxyController.Start(MainController.Server!);
|
||||
Global.Job.AddProcess(PrivoxyController.Instance!);
|
||||
string? pacUrl = null;
|
||||
|
||||
if (MainController.Server is Socks5 or Trojan && mode.BypassChina || (Global.Settings.AlwaysStartPACServer ?? false))
|
||||
@@ -38,7 +37,7 @@ namespace Netch.Controllers
|
||||
Global.Settings.Pac_Port = PortHelper.GetAvailablePort();
|
||||
}
|
||||
|
||||
pacUrl = PACServerHandle.InitPACServer("127.0.0.1");
|
||||
pacUrl = PACServerHandle.InitPACServer();
|
||||
}
|
||||
|
||||
if (mode.Type is 3)
|
||||
@@ -76,7 +75,14 @@ namespace Netch.Controllers
|
||||
if (_oldState != null)
|
||||
{
|
||||
using var service = new ProxyService();
|
||||
service.Set(_oldState!);
|
||||
if (_oldState.IsProxy && _oldState.ProxyServer == service.Query().ProxyServer ||
|
||||
_oldState.IsAutoProxyUrl && _oldState.AutoConfigUrl!.StartsWith(PACServerHandle.PacPrefix))
|
||||
{
|
||||
service.Direct();
|
||||
return;
|
||||
}
|
||||
|
||||
service.Set(_oldState);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using static Netch.Utils.PortHelper;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -49,7 +48,12 @@ namespace Netch.Controllers
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
/// <exception cref="MessageException"></exception>
|
||||
public static async Task Start(Server server, Mode mode)
|
||||
public static async Task StartAsync(Server server, Mode mode)
|
||||
{
|
||||
await Task.Run(() => Start(server, mode));
|
||||
}
|
||||
|
||||
public static void Start(Server server, Mode mode)
|
||||
{
|
||||
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
Server = server;
|
||||
@@ -71,23 +75,15 @@ namespace Netch.Controllers
|
||||
{
|
||||
if (!ModeHelper.SkipServerController(server, mode))
|
||||
{
|
||||
await Task.Run(() => StartServer(server, mode, out _serverController));
|
||||
|
||||
StartServer(server, mode, out _serverController);
|
||||
StatusPortInfoText.UpdateShareLan();
|
||||
}
|
||||
|
||||
await Task.Run(() => StartMode(mode));
|
||||
StartMode(mode);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Stop();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Stop();
|
||||
|
||||
switch (e)
|
||||
{
|
||||
@@ -108,20 +104,11 @@ namespace Netch.Controllers
|
||||
{
|
||||
controller = ServerHelper.GetUtilByTypeName(server.Type).GetController();
|
||||
|
||||
if (controller is Guard instanceController)
|
||||
Utils.Utils.KillProcessByName(instanceController.MainFile);
|
||||
|
||||
PortCheck(controller.Socks5LocalPort(), "Socks5");
|
||||
TryReleaseTcpPort(controller.Socks5LocalPort(), "Socks5");
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
|
||||
|
||||
controller.Start(in server, mode);
|
||||
if (controller is Guard {Instance: { }} guard)
|
||||
Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Global.Job.AddProcess(guard.Instance!);
|
||||
});
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
@@ -136,25 +123,28 @@ namespace Netch.Controllers
|
||||
|
||||
private static void StartMode(Mode mode)
|
||||
{
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName, out var portType);
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName);
|
||||
|
||||
if (ModeController == null)
|
||||
return;
|
||||
|
||||
if (port != null)
|
||||
PortCheck((ushort) port, portName, portType);
|
||||
TryReleaseTcpPort((ushort) port, portName);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
|
||||
ModeController.Start(mode);
|
||||
if (ModeController is Guard {Instance: { }} guard)
|
||||
Global.Job.AddProcess(guard.Instance!);
|
||||
}
|
||||
|
||||
public static async Task StopAsync()
|
||||
{
|
||||
await Task.Run(Stop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public static async Task Stop()
|
||||
public static void Stop()
|
||||
{
|
||||
if (_serverController == null && ModeController == null)
|
||||
return;
|
||||
@@ -169,7 +159,16 @@ namespace Netch.Controllers
|
||||
Task.Run(() => ModeController?.Stop())
|
||||
};
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
}
|
||||
|
||||
ModeController = null;
|
||||
ServerController = null;
|
||||
}
|
||||
@@ -178,7 +177,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
CheckPort(port, portType);
|
||||
PortHelper.CheckPort(port, portType);
|
||||
}
|
||||
catch (PortInUseException)
|
||||
{
|
||||
@@ -189,6 +188,27 @@ namespace Netch.Controllers
|
||||
throw new MessageException(i18N.TranslateFormat("The {0} port is reserved by system.", $"{portName} ({port})"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void TryReleaseTcpPort(ushort port, string portName)
|
||||
{
|
||||
Process? p;
|
||||
if ((p = PortHelper.GetProcessByUsedTcpPort(port)) != null)
|
||||
{
|
||||
if (p.MainModule!.FileName.StartsWith(Global.NetchDir))
|
||||
{
|
||||
p.Kill();
|
||||
p.WaitForExit();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageException(i18N.TranslateFormat("The {0} port is used by {1}.",
|
||||
$"{portName} ({port})",
|
||||
$"({p.Id}){p.MainModule.FileName}"));
|
||||
}
|
||||
}
|
||||
|
||||
PortCheck(port, portName, PortType.TCP);
|
||||
}
|
||||
}
|
||||
|
||||
public class MessageException : Exception
|
||||
|
||||
@@ -17,67 +17,30 @@ namespace Netch.Controllers
|
||||
{
|
||||
private static readonly ServiceController NFService = new("netfilter2");
|
||||
|
||||
private static readonly string BinDriver;
|
||||
private const string BinDriver = "bin\\nfdriver.sys";
|
||||
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
|
||||
|
||||
private static string? _sysDns;
|
||||
private OutboundAdapter? _outbound;
|
||||
|
||||
static NFController()
|
||||
{
|
||||
string fileName;
|
||||
switch ($"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor}")
|
||||
{
|
||||
case "10.0":
|
||||
fileName = "Win-10.sys";
|
||||
break;
|
||||
case "6.3":
|
||||
case "6.2":
|
||||
fileName = "Win-8.sys";
|
||||
break;
|
||||
case "6.1":
|
||||
case "6.0":
|
||||
fileName = "Win-7.sys";
|
||||
break;
|
||||
default:
|
||||
throw new MessageException($"不支持的系统版本:{Environment.OSVersion.Version}");
|
||||
}
|
||||
|
||||
BinDriver = "bin\\" + fileName;
|
||||
}
|
||||
|
||||
public string Name { get; } = "Redirector";
|
||||
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
CheckDriver();
|
||||
|
||||
#region aio_dial
|
||||
|
||||
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
|
||||
|
||||
// Server
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, (Global.Settings.ProcessProxyProtocol != PortType.TCP).ToString().ToLower());
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, (Global.Settings.ProcessProxyProtocol != PortType.UDP).ToString().ToLower());
|
||||
SetServer(Global.Settings.ProcessProxyProtocol);
|
||||
dial_Server(Global.Settings.ProcessProxyProtocol);
|
||||
|
||||
if (!CheckRule(mode.FullRule, out var list))
|
||||
throw new MessageException($"\"{string.Join("", list.Select(s => s + "\n"))}\" does not conform to C++ regular expression syntax");
|
||||
// Mode Rule
|
||||
dial_Name(mode);
|
||||
|
||||
SetName(mode);
|
||||
|
||||
#endregion
|
||||
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
{
|
||||
_outbound = new OutboundAdapter();
|
||||
// 备份并替换系统 DNS
|
||||
_sysDns = _outbound.DNS;
|
||||
if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS))
|
||||
Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8";
|
||||
|
||||
_outbound.DNS = Global.Settings.ModifiedDNS;
|
||||
}
|
||||
// Features
|
||||
aio_dial((int) NameList.TYPE_REDIRCTOR_DNS, Global.Settings.RedirectDNS ? Global.Settings.RedirectDNSAddr : "");
|
||||
aio_dial((int) NameList.TYPE_REDIRCTOR_ICMP, Global.Settings.RedirectICMP ? Global.Settings.RedirectICMPAddr : "");
|
||||
aio_dial((int) NameList.TYPE_FILTERCHILDPROC, Global.Settings.ChildProcessHandle.ToString().ToLower());
|
||||
|
||||
if (!aio_init())
|
||||
throw new MessageException("Redirector Start failed, run Netch with \"-console\" argument");
|
||||
@@ -85,34 +48,17 @@ namespace Netch.Controllers
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
//恢复系统DNS
|
||||
_outbound!.DNS = _sysDns!;
|
||||
});
|
||||
|
||||
aio_free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="rules"></param>
|
||||
/// <param name="incompatibleRule"></param>
|
||||
/// <returns>No Problem true</returns>
|
||||
public static bool CheckRule(IEnumerable<string> rules, out IEnumerable<string> incompatibleRule)
|
||||
{
|
||||
incompatibleRule = rules.Where(r => !CheckCppRegex(r, false));
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
return !incompatibleRule.Any();
|
||||
}
|
||||
#region CheckRule
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="clear"></param>
|
||||
/// <returns>No Problem true</returns>
|
||||
public static bool CheckCppRegex(string r, bool clear = true)
|
||||
private static bool CheckCppRegex(string r, bool clear = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -128,50 +74,31 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckDriver()
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="rules"></param>
|
||||
/// <param name="results"></param>
|
||||
/// <returns>No Problem true</returns>
|
||||
public static bool CheckRules(IEnumerable<string> rules, out IEnumerable<string> results)
|
||||
{
|
||||
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
|
||||
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
|
||||
|
||||
Logging.Info("内置驱动版本: " + binFileVersion);
|
||||
Logging.Info("系统驱动版本: " + systemFileVersion);
|
||||
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
InstallDriver();
|
||||
return;
|
||||
}
|
||||
|
||||
var reinstallFlag = false;
|
||||
if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
|
||||
{
|
||||
if (binResult.CompareTo(systemResult) > 0)
|
||||
// Bin greater than Installed
|
||||
reinstallFlag = true;
|
||||
else if (systemResult.Major != binResult.Major)
|
||||
// Installed greater than Bin but Major Version Difference (has breaking changes), do downgrade
|
||||
reinstallFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!systemFileVersion.Equals(binFileVersion))
|
||||
reinstallFlag = true;
|
||||
}
|
||||
|
||||
if (!reinstallFlag)
|
||||
return;
|
||||
|
||||
Logging.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
InstallDriver();
|
||||
results = rules.Where(r => !CheckCppRegex(r, false));
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
return !results.Any();
|
||||
}
|
||||
|
||||
private void SetServer(in PortType portType)
|
||||
public static string GenerateInvalidRulesMessage(IEnumerable<string> rules)
|
||||
{
|
||||
return $"{string.Join("\n", rules)}\nAbove rules does not conform to C++ regular expression syntax";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void dial_Server(in PortType portType)
|
||||
{
|
||||
if (portType == PortType.Both)
|
||||
{
|
||||
SetServer(PortType.TCP);
|
||||
SetServer(PortType.UDP);
|
||||
dial_Server(PortType.TCP);
|
||||
dial_Server(PortType.UDP);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -204,8 +131,8 @@ namespace Netch.Controllers
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, shadowsocks.Password ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, shadowsocks.Password);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -217,68 +144,74 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private void SetName(Mode mode)
|
||||
private void dial_Name(Mode mode)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
foreach (var rule in mode.FullRule)
|
||||
var list = new List<string>();
|
||||
foreach (var s in mode.FullRule)
|
||||
{
|
||||
if (rule.StartsWith("!"))
|
||||
if (s.StartsWith("!"))
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_BYPNAME, rule.Substring(1));
|
||||
if (!aio_dial((int) NameList.TYPE_BYPNAME, s.Substring(1)))
|
||||
list.Add(s);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, rule);
|
||||
if (!aio_dial((int) NameList.TYPE_ADDNAME, s))
|
||||
list.Add(s);
|
||||
}
|
||||
|
||||
if (list.Any())
|
||||
throw new MessageException(GenerateInvalidRulesMessage(list));
|
||||
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, @"NTT\.exe");
|
||||
aio_dial((int) NameList.TYPE_BYPNAME, "^" + Global.NetchDir.ToRegexString() + @"((?!NTT\.exe).)*$");
|
||||
}
|
||||
|
||||
#region NativeMethods
|
||||
#region DriverUtil
|
||||
|
||||
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_init();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_free();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getUP();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getDL();
|
||||
|
||||
public enum NameList
|
||||
private static void CheckDriver()
|
||||
{
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
TYPE_TCPLISN,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_ADDNAME,
|
||||
TYPE_BYPNAME,
|
||||
TYPE_CLRNAME
|
||||
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
|
||||
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
|
||||
|
||||
Logging.Info("内置驱动版本: " + binFileVersion);
|
||||
Logging.Info("系统驱动版本: " + systemFileVersion);
|
||||
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
// Install
|
||||
InstallDriver();
|
||||
return;
|
||||
}
|
||||
|
||||
var reinstall = false;
|
||||
if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
|
||||
{
|
||||
if (binResult.CompareTo(systemResult) > 0)
|
||||
// Update
|
||||
reinstall = true;
|
||||
else if (systemResult.Major != binResult.Major)
|
||||
// Downgrade when Major version different (may have breaking changes)
|
||||
reinstall = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse File versionName to Version failed
|
||||
if (!systemFileVersion.Equals(binFileVersion))
|
||||
// versionNames are different, Reinstall
|
||||
reinstall = true;
|
||||
}
|
||||
|
||||
if (!reinstall)
|
||||
return;
|
||||
|
||||
Logging.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
InstallDriver();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
|
||||
/// <summary>
|
||||
/// 安装 NF 驱动
|
||||
/// </summary>
|
||||
@@ -344,5 +277,61 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region NativeMethods
|
||||
|
||||
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_init();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_free();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getUP();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getDL();
|
||||
|
||||
public enum NameList
|
||||
{
|
||||
//bool
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
TYPE_FILTERIP,
|
||||
TYPE_FILTERCHILDPROC, //子进程捕获
|
||||
|
||||
TYPE_TCPLISN,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
|
||||
TYPE_ADDNAME,
|
||||
TYPE_ADDFIP,
|
||||
|
||||
TYPE_BYPNAME,
|
||||
|
||||
TYPE_CLRNAME,
|
||||
TYPE_CLRFIP,
|
||||
|
||||
//str addr x.x.x.x only ipv4
|
||||
TYPE_REDIRCTOR_DNS,
|
||||
TYPE_REDIRCTOR_ICMP
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -22,31 +23,37 @@ namespace Netch.Controllers
|
||||
|
||||
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
public PcapController()
|
||||
{
|
||||
RedirectToFile = false;
|
||||
}
|
||||
|
||||
private LogForm? _form;
|
||||
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() =>
|
||||
{
|
||||
_form = new LogForm(Global.MainForm);
|
||||
_form.Show();
|
||||
}));
|
||||
var server = MainController.Server!;
|
||||
|
||||
StartInstanceAuto($@"-i \Device\NPF_{_outbound.NetworkInterface.Id} {mode.FullRule.FirstOrDefault() ?? "-P n"}");
|
||||
_form = new LogForm(Global.MainForm);
|
||||
_form.CreateControl();
|
||||
|
||||
var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}");
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
argument.Append($" --destination {server.AutoResolveHostname()}:{server.Port}");
|
||||
else
|
||||
argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
|
||||
argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}");
|
||||
StartInstanceAuto(argument.ToString());
|
||||
}
|
||||
|
||||
protected override void OnReadNewLine(string line)
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() => { _form!.richTextBox1.AppendText(line + "\n"); }));
|
||||
Global.MainForm.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (!_form!.IsDisposed)
|
||||
_form.richTextBox1.AppendText(line + "\n");
|
||||
}));
|
||||
}
|
||||
|
||||
protected override void OnKeywordStarted()
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() => { _form!.Show(); }));
|
||||
}
|
||||
|
||||
protected override void OnKeywordStopped()
|
||||
@@ -67,8 +74,7 @@ namespace Netch.Controllers
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
Global.MainForm.Invoke(new Action(() => { _form!.Close(); }));
|
||||
|
||||
_form!.Close();
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Netch.Controllers
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2021";
|
||||
|
||||
public const string AssemblyVersion = @"1.8.0";
|
||||
private const string Suffix = @"";
|
||||
public const string AssemblyVersion = @"1.8.3";
|
||||
private const string Suffix = @"Beta1";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
@@ -69,31 +69,25 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetFileNameAndHashFromMarkdownForm(in string text, out string fileName, out string sha256, string? keyword = null)
|
||||
public static void GetLatestUpdateFileNameAndHash(out string fileName, out string sha256, string? keyword = null)
|
||||
{
|
||||
IEnumerable<Match> matches;
|
||||
try
|
||||
{
|
||||
matches = Regex.Matches(text, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline).Cast<Match>().Skip(2);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
throw new Exception(i18N.Translate("Find update filename and hash failed"));
|
||||
}
|
||||
fileName = string.Empty;
|
||||
sha256 = string.Empty;
|
||||
|
||||
var matches = Regex.Matches(LatestRelease.body, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline)
|
||||
.Cast<Match>()
|
||||
.Skip(2);
|
||||
/*
|
||||
Skip(2)
|
||||
|
||||
| 文件名 | SHA256 |
|
||||
| :- | :- |
|
||||
*/
|
||||
|
||||
Match match = keyword == null ? matches.First() : matches.First(m => m.Groups["filename"].Value.Contains(keyword));
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
fileName = match.Groups["filename"].Value;
|
||||
sha256 = match.Groups["sha256"].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
fileName = string.Empty;
|
||||
sha256 = string.Empty;
|
||||
return false;
|
||||
fileName = match.Groups["filename"].Value;
|
||||
sha256 = match.Groups["sha256"].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,9 @@ namespace Netch.Forms
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
base.OnLoad(e);
|
||||
Parent_Move(null!, null!);
|
||||
}
|
||||
|
||||
|
||||
4
Netch/Forms/MainForm.Designer.cs
generated
@@ -423,7 +423,7 @@
|
||||
this.ModeComboBox.Size = new System.Drawing.Size(546, 24);
|
||||
this.ModeComboBox.TabIndex = 2;
|
||||
this.ModeComboBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ComboBox_DrawItem);
|
||||
this.ModeComboBox.SelectedIndexChanged += new System.EventHandler(this.ModeComboBox_SelectedIndexChanged);
|
||||
this.ModeComboBox.SelectionChangeCommitted += new System.EventHandler(this.ModeComboBox_SelectionChangeCommitted);
|
||||
//
|
||||
// ServerComboBox
|
||||
//
|
||||
@@ -438,7 +438,7 @@
|
||||
this.ServerComboBox.Size = new System.Drawing.Size(546, 24);
|
||||
this.ServerComboBox.TabIndex = 1;
|
||||
this.ServerComboBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ComboBox_DrawItem);
|
||||
this.ServerComboBox.SelectedIndexChanged += new System.EventHandler(this.ServerComboBox_SelectedIndexChanged);
|
||||
this.ServerComboBox.SelectionChangeCommitted += new System.EventHandler(this.ServerComboBox_SelectionChangeCommitted);
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace Netch.Forms
|
||||
|
||||
private readonly Dictionary<string, object> _mainFormText = new();
|
||||
|
||||
private bool _comboBoxInitialized;
|
||||
private bool _textRecorded;
|
||||
|
||||
public MainForm()
|
||||
@@ -85,7 +84,7 @@ namespace Netch.Forms
|
||||
|
||||
private void MainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
OnlyInstance.Called += OnCalled;
|
||||
Netch.TimePoint("MainForm ctor (Pre MainForm Load)");
|
||||
|
||||
// 计算 ComboBox绘制 目标宽度
|
||||
RecordSize();
|
||||
@@ -95,7 +94,6 @@ namespace Netch.Forms
|
||||
|
||||
ModeHelper.Load();
|
||||
LoadModes();
|
||||
_comboBoxInitialized = true;
|
||||
|
||||
// 加载翻译
|
||||
TranslateControls();
|
||||
@@ -106,10 +104,6 @@ namespace Netch.Forms
|
||||
// 加载快速配置
|
||||
LoadProfiles();
|
||||
|
||||
// 打开软件时启动加速,产生开始按钮点击事件
|
||||
if (Global.Settings.StartWhenOpened)
|
||||
ControlButton_Click(null, null);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
// 检查更新
|
||||
@@ -117,12 +111,18 @@ namespace Netch.Forms
|
||||
CheckUpdate();
|
||||
});
|
||||
|
||||
Task.Run(async () =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
// 检查订阅更新
|
||||
if (Global.Settings.UpdateServersWhenOpened)
|
||||
await UpdateServersFromSubscribe(Global.Settings.UseProxyToUpdateSubscription);
|
||||
UpdateServersFromSubscribe(Global.Settings.UseProxyToUpdateSubscription).Wait();
|
||||
|
||||
// 打开软件时启动加速,产生开始按钮点击事件
|
||||
if (Global.Settings.StartWhenOpened)
|
||||
ControlButton_Click(null, null);
|
||||
});
|
||||
|
||||
Netch.TimePoint("Post Form Load", false);
|
||||
}
|
||||
|
||||
private void RecordSize()
|
||||
@@ -345,7 +345,7 @@ namespace Netch.Forms
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.Start(server!, mode);
|
||||
await MainController.StartAsync(server!, mode);
|
||||
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
}
|
||||
|
||||
@@ -363,14 +363,7 @@ namespace Netch.Forms
|
||||
finally
|
||||
{
|
||||
if (useProxy)
|
||||
try
|
||||
{
|
||||
await MainController.Stop();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
await MainController.StopAsync();
|
||||
|
||||
DisableItems(true);
|
||||
}
|
||||
@@ -386,19 +379,25 @@ namespace Netch.Forms
|
||||
{
|
||||
void OnNewVersionNotFound(object o, EventArgs args)
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound -= OnNewVersionNotFound;
|
||||
NotifyTip(i18N.Translate("Already latest version"));
|
||||
}
|
||||
|
||||
void OnNewVersionFoundFailed(object o, EventArgs args)
|
||||
{
|
||||
UpdateChecker.NewVersionFoundFailed -= OnNewVersionFoundFailed;
|
||||
NotifyTip(i18N.Translate("New version found failed"), info: false);
|
||||
}
|
||||
|
||||
UpdateChecker.NewVersionNotFound += OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed += OnNewVersionFoundFailed;
|
||||
CheckUpdate();
|
||||
try
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound += OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed += OnNewVersionFoundFailed;
|
||||
CheckUpdate();
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound -= OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed -= OnNewVersionFoundFailed;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -460,7 +459,7 @@ namespace Netch.Forms
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.Start(server, mode);
|
||||
await MainController.StartAsync(server, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,7 +478,7 @@ namespace Netch.Forms
|
||||
finally
|
||||
{
|
||||
if (useProxy)
|
||||
await MainController.Stop();
|
||||
await MainController.StopAsync();
|
||||
|
||||
StatusText();
|
||||
Enabled = true;
|
||||
@@ -572,6 +571,47 @@ namespace Netch.Forms
|
||||
Utils.Utils.Open($"https://github.com/{UpdateChecker.Owner}/{UpdateChecker.Repo}/releases");
|
||||
}
|
||||
|
||||
private async void NewVersionLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Control || !UpdateChecker.LatestRelease!.assets.Any())
|
||||
{
|
||||
Utils.Utils.Open(UpdateChecker.LatestVersionUrl!);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
NotifyTip(i18N.Translate("Start downloading new version"));
|
||||
NewVersionLabel.Enabled = false;
|
||||
NewVersionLabel.Text = "...";
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Updater.Updater.DownloadAndUpdate(Path.Combine(Global.NetchDir, "data"),
|
||||
Global.NetchDir,
|
||||
(_, args) => BeginInvoke(new Action(() => NewVersionLabel.Text = $"{args.ProgressPercentage}%")));
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is not MessageException)
|
||||
{
|
||||
Logging.Error($"更新失败: {exception}");
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
}
|
||||
|
||||
NotifyTip(exception.Message, info: false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NewVersionLabel.Visible = false;
|
||||
NewVersionLabel.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void AboutToolStripButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Hide();
|
||||
@@ -594,7 +634,7 @@ namespace Netch.Forms
|
||||
{
|
||||
// 停止
|
||||
State = State.Stopping;
|
||||
await MainController.Stop();
|
||||
await MainController.StopAsync();
|
||||
State = State.Stopped;
|
||||
return;
|
||||
}
|
||||
@@ -621,13 +661,13 @@ namespace Netch.Forms
|
||||
|
||||
try
|
||||
{
|
||||
await MainController.Start(server, mode);
|
||||
await MainController.StartAsync(server, mode);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
State = State.Stopped;
|
||||
StatusText(i18N.Translate("Start failed"));
|
||||
MessageBoxX.Show(exception.Message);
|
||||
MessageBoxX.Show(exception.Message, LogLevel.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -697,13 +737,9 @@ namespace Netch.Forms
|
||||
|
||||
private void LoadServers()
|
||||
{
|
||||
var comboBoxInitialized = _comboBoxInitialized;
|
||||
_comboBoxInitialized = false;
|
||||
|
||||
ServerComboBox.Items.Clear();
|
||||
ServerComboBox.Items.AddRange(Global.Settings.Server.ToArray());
|
||||
SelectLastServer();
|
||||
_comboBoxInitialized = comboBoxInitialized;
|
||||
}
|
||||
|
||||
public void SelectLastServer()
|
||||
@@ -718,11 +754,8 @@ namespace Netch.Forms
|
||||
// 如果当前 ServerComboBox 中没元素,不做处理
|
||||
}
|
||||
|
||||
private void ServerComboBox_SelectedIndexChanged(object sender, EventArgs o)
|
||||
private void ServerComboBox_SelectionChangeCommitted(object sender, EventArgs o)
|
||||
{
|
||||
if (!_comboBoxInitialized)
|
||||
return;
|
||||
|
||||
Global.Settings.ServerComboBoxSelectedIndex = ServerComboBox.SelectedIndex;
|
||||
}
|
||||
|
||||
@@ -821,14 +854,10 @@ namespace Netch.Forms
|
||||
|
||||
public void LoadModes()
|
||||
{
|
||||
var comboBoxInitialized = _comboBoxInitialized;
|
||||
_comboBoxInitialized = false;
|
||||
|
||||
ModeComboBox.Items.Clear();
|
||||
ModeComboBox.Items.AddRange(Global.Modes.ToArray());
|
||||
ModeComboBox.Items.AddRange(Global.Modes.Cast<object>().ToArray());
|
||||
ModeComboBox.Tag = null;
|
||||
SelectLastMode();
|
||||
_comboBoxInitialized = comboBoxInitialized;
|
||||
}
|
||||
|
||||
public void SelectLastMode()
|
||||
@@ -843,11 +872,8 @@ namespace Netch.Forms
|
||||
// 如果当前 ModeComboBox 中没元素,不做处理
|
||||
}
|
||||
|
||||
private void ModeComboBox_SelectedIndexChanged(object sender, EventArgs o)
|
||||
private void ModeComboBox_SelectionChangeCommitted(object sender, EventArgs o)
|
||||
{
|
||||
if (!_comboBoxInitialized)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode) ModeComboBox.SelectedItem);
|
||||
@@ -1362,27 +1388,12 @@ namespace Netch.Forms
|
||||
File.Delete(file);
|
||||
|
||||
if (!IsWaiting())
|
||||
await MainController.Stop();
|
||||
await MainController.StopAsync();
|
||||
|
||||
Dispose();
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
}
|
||||
|
||||
private void OnCalled(object sender, OnlyInstance.Commands e)
|
||||
{
|
||||
switch (e)
|
||||
{
|
||||
case OnlyInstance.Commands.Show:
|
||||
NotifyIcon_MouseDoubleClick(null, null);
|
||||
break;
|
||||
case OnlyInstance.Commands.Exit:
|
||||
Exit(true);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(e), e, null);
|
||||
}
|
||||
}
|
||||
|
||||
#region FormClosingButton
|
||||
|
||||
private bool _isFirstCloseWindow = true;
|
||||
@@ -1409,43 +1420,22 @@ namespace Netch.Forms
|
||||
|
||||
private void CheckUpdate()
|
||||
{
|
||||
UpdateChecker.NewVersionFound += (_, _) =>
|
||||
{
|
||||
NotifyTip($"{i18N.Translate(@"New version available", ": ")}{UpdateChecker.LatestVersionNumber}");
|
||||
NewVersionLabel.Visible = true;
|
||||
};
|
||||
|
||||
UpdateChecker.Check(Global.Settings.CheckBetaUpdate).Wait();
|
||||
}
|
||||
|
||||
private async void NewVersionLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Control || !UpdateChecker.LatestRelease!.assets.Any())
|
||||
{
|
||||
Utils.Utils.Open(UpdateChecker.LatestVersionUrl!);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
NotifyTip(i18N.Translate("Start downloading new version"));
|
||||
|
||||
NewVersionLabel.Enabled = false;
|
||||
NewVersionLabel.Text = "...";
|
||||
try
|
||||
{
|
||||
void OnDownloadProgressChanged(object o1, DownloadProgressChangedEventArgs args)
|
||||
{
|
||||
BeginInvoke(new Action(() => { NewVersionLabel.Text = $"{args.ProgressPercentage}%"; }));
|
||||
}
|
||||
|
||||
await Updater.Updater.DownloadAndUpdate(Path.Combine(Global.NetchDir, "data"), Global.NetchDir, OnDownloadProgressChanged);
|
||||
UpdateChecker.NewVersionFound += OnUpdateCheckerOnNewVersionFound;
|
||||
UpdateChecker.Check(Global.Settings.CheckBetaUpdate).Wait();
|
||||
}
|
||||
catch (Exception exception)
|
||||
finally
|
||||
{
|
||||
Logging.Error(exception.Message);
|
||||
NotifyTip(exception.Message);
|
||||
UpdateChecker.NewVersionFound -= OnUpdateCheckerOnNewVersionFound;
|
||||
}
|
||||
|
||||
void OnUpdateCheckerOnNewVersionFound(object o, EventArgs eventArgs)
|
||||
{
|
||||
NotifyTip($"{i18N.Translate(@"New version available", ": ")}{UpdateChecker.LatestVersionNumber}");
|
||||
NewVersionLabel.Text = i18N.Translate("New version available");
|
||||
NewVersionLabel.Enabled = true;
|
||||
NewVersionLabel.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,5 +13,15 @@ namespace Netch.Forms.Mode
|
||||
|
||||
return fileName.ToString();
|
||||
}
|
||||
|
||||
public static string GetCustomModeRelativePath(string name)
|
||||
{
|
||||
if (name == string.Empty)
|
||||
return string.Empty;
|
||||
|
||||
var safeFileName = ToSafeFileName(name);
|
||||
var relativePath = $"Custom\\{safeFileName}.txt";
|
||||
return relativePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
250
Netch/Forms/Mode/Process.Designer.cs
generated
@@ -31,129 +31,40 @@ namespace Netch.Forms.Mode
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Process));
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.UseCustomFilenameBox = new System.Windows.Forms.CheckBox();
|
||||
this.RemarkLabel = new System.Windows.Forms.Label();
|
||||
this.RemarkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.FilenameLabel = new System.Windows.Forms.Label();
|
||||
this.FilenameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ScanButton = new System.Windows.Forms.Button();
|
||||
this.ProcessGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.AddButton = new System.Windows.Forms.Button();
|
||||
this.ProcessNameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RuleListBox = new System.Windows.Forms.ListBox();
|
||||
this.RemarkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RemarkLabel = new System.Windows.Forms.Label();
|
||||
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.containerControl1 = new System.Windows.Forms.ContainerControl();
|
||||
this.RuleRichTextBox = new System.Windows.Forms.RichTextBox();
|
||||
this.ProcessGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.SelectButton = new System.Windows.Forms.Button();
|
||||
this.ScanButton = new System.Windows.Forms.Button();
|
||||
this.ValidationButton = new System.Windows.Forms.Button();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
this.ConfigurationGroupBox.SuspendLayout();
|
||||
this.ProcessGroupBox.SuspendLayout();
|
||||
this.contextMenuStrip.SuspendLayout();
|
||||
this.containerControl1.SuspendLayout();
|
||||
this.ProcessGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// ConfigurationGroupBox
|
||||
//
|
||||
this.ConfigurationGroupBox.Controls.Add(this.containerControl1);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.UseCustomFilenameBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.FilenameLabel);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.FilenameTextBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.ScanButton);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.containerControl1);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.ProcessGroupBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel);
|
||||
this.ConfigurationGroupBox.Location = new System.Drawing.Point(12, 12);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.ControlButton);
|
||||
this.ConfigurationGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ConfigurationGroupBox.Location = new System.Drawing.Point(12, 5);
|
||||
this.ConfigurationGroupBox.Name = "ConfigurationGroupBox";
|
||||
this.ConfigurationGroupBox.Size = new System.Drawing.Size(340, 344);
|
||||
this.ConfigurationGroupBox.Size = new System.Drawing.Size(431, 378);
|
||||
this.ConfigurationGroupBox.TabIndex = 0;
|
||||
this.ConfigurationGroupBox.TabStop = false;
|
||||
this.ConfigurationGroupBox.Text = "Configuration";
|
||||
//
|
||||
// UseCustomFilenameBox
|
||||
//
|
||||
this.UseCustomFilenameBox.AutoSize = true;
|
||||
this.UseCustomFilenameBox.Location = new System.Drawing.Point(84, 76);
|
||||
this.UseCustomFilenameBox.Name = "UseCustomFilenameBox";
|
||||
this.UseCustomFilenameBox.Size = new System.Drawing.Size(152, 21);
|
||||
this.UseCustomFilenameBox.TabIndex = 9;
|
||||
this.UseCustomFilenameBox.Text = "Use Custom Filename";
|
||||
this.UseCustomFilenameBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FilenameLabel
|
||||
//
|
||||
this.FilenameLabel.AutoSize = true;
|
||||
this.FilenameLabel.Location = new System.Drawing.Point(12, 55);
|
||||
this.FilenameLabel.Name = "FilenameLabel";
|
||||
this.FilenameLabel.Size = new System.Drawing.Size(59, 17);
|
||||
this.FilenameLabel.TabIndex = 6;
|
||||
this.FilenameLabel.Text = "Filename";
|
||||
//
|
||||
// FilenameTextBox
|
||||
//
|
||||
this.FilenameTextBox.Location = new System.Drawing.Point(84, 52);
|
||||
this.FilenameTextBox.Name = "FilenameTextBox";
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(250, 23);
|
||||
this.FilenameTextBox.TabIndex = 5;
|
||||
this.FilenameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.UseCustomFilenameBox, "Checked", true));;
|
||||
//
|
||||
// ScanButton
|
||||
//
|
||||
this.ScanButton.Location = new System.Drawing.Point(6, 315);
|
||||
this.ScanButton.Name = "ScanButton";
|
||||
this.ScanButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ScanButton.TabIndex = 4;
|
||||
this.ScanButton.Text = "Scan";
|
||||
this.ScanButton.UseVisualStyleBackColor = true;
|
||||
this.ScanButton.Click += new System.EventHandler(this.ScanButton_Click);
|
||||
//
|
||||
// ProcessGroupBox
|
||||
//
|
||||
this.ProcessGroupBox.Controls.Add(this.AddButton);
|
||||
this.ProcessGroupBox.Controls.Add(this.ProcessNameTextBox);
|
||||
this.ProcessGroupBox.Location = new System.Drawing.Point(6, 263);
|
||||
this.ProcessGroupBox.Name = "ProcessGroupBox";
|
||||
this.ProcessGroupBox.Size = new System.Drawing.Size(328, 46);
|
||||
this.ProcessGroupBox.TabIndex = 3;
|
||||
this.ProcessGroupBox.TabStop = false;
|
||||
//
|
||||
// AddButton
|
||||
//
|
||||
this.AddButton.Location = new System.Drawing.Point(247, 15);
|
||||
this.AddButton.Name = "AddButton";
|
||||
this.AddButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.AddButton.TabIndex = 1;
|
||||
this.AddButton.Text = "Add";
|
||||
this.AddButton.UseVisualStyleBackColor = true;
|
||||
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
|
||||
//
|
||||
// ProcessNameTextBox
|
||||
//
|
||||
this.ProcessNameTextBox.Location = new System.Drawing.Point(6, 15);
|
||||
this.ProcessNameTextBox.Name = "ProcessNameTextBox";
|
||||
this.ProcessNameTextBox.Size = new System.Drawing.Size(222, 23);
|
||||
this.ProcessNameTextBox.TabIndex = 0;
|
||||
//
|
||||
// RuleListBox
|
||||
//
|
||||
this.RuleListBox.FormattingEnabled = true;
|
||||
this.RuleListBox.Dock = DockStyle.Fill;
|
||||
this.RuleListBox.ItemHeight = 17;
|
||||
this.RuleListBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.RuleListBox.Name = "RuleListBox";
|
||||
this.RuleListBox.Size = new System.Drawing.Size(328, 157);
|
||||
this.RuleListBox.TabIndex = 2;
|
||||
this.RuleListBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.RuleListBox_MouseUp);
|
||||
//
|
||||
// RemarkTextBox
|
||||
//
|
||||
this.RemarkTextBox.Location = new System.Drawing.Point(84, 22);
|
||||
this.RemarkTextBox.Name = "RemarkTextBox";
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(250, 23);
|
||||
this.RemarkTextBox.TabIndex = 1;
|
||||
this.RemarkTextBox.TextChanged += new System.EventHandler(this.RemarkTextBox_TextChanged);
|
||||
//
|
||||
// RemarkLabel
|
||||
//
|
||||
this.RemarkLabel.AutoSize = true;
|
||||
@@ -163,79 +74,138 @@ namespace Netch.Forms.Mode
|
||||
this.RemarkLabel.TabIndex = 0;
|
||||
this.RemarkLabel.Text = "Remark";
|
||||
//
|
||||
// contextMenuStrip
|
||||
// RemarkTextBox
|
||||
//
|
||||
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.DeleteToolStripMenuItem});
|
||||
this.contextMenuStrip.Name = "contextMenuStrip";
|
||||
this.contextMenuStrip.Size = new System.Drawing.Size(153, 48);
|
||||
this.RemarkTextBox.Location = new System.Drawing.Point(84, 22);
|
||||
this.RemarkTextBox.Name = "RemarkTextBox";
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(341, 23);
|
||||
this.RemarkTextBox.TabIndex = 1;
|
||||
this.RemarkTextBox.TextChanged += new System.EventHandler(this.RemarkTextBox_TextChanged);
|
||||
//
|
||||
// ControlButton
|
||||
// FilenameLabel
|
||||
//
|
||||
this.ControlButton.Location = new System.Drawing.Point(277, 362);
|
||||
this.ControlButton.Name = "ControlButton";
|
||||
this.ControlButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ControlButton.TabIndex = 1;
|
||||
this.ControlButton.Text = "Save";
|
||||
this.ControlButton.UseVisualStyleBackColor = true;
|
||||
this.ControlButton.Click += new System.EventHandler(this.ControlButton_Click);
|
||||
this.FilenameLabel.AutoSize = true;
|
||||
this.FilenameLabel.Location = new System.Drawing.Point(12, 55);
|
||||
this.FilenameLabel.Name = "FilenameLabel";
|
||||
this.FilenameLabel.Size = new System.Drawing.Size(59, 17);
|
||||
this.FilenameLabel.TabIndex = 2;
|
||||
this.FilenameLabel.Text = "Filename";
|
||||
//
|
||||
// DeleteToolStripMenuItem
|
||||
// FilenameTextBox
|
||||
//
|
||||
this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
|
||||
this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.DeleteToolStripMenuItem.Text = "Delete";
|
||||
this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.deleteRule_Click);
|
||||
this.FilenameTextBox.Location = new System.Drawing.Point(84, 52);
|
||||
this.FilenameTextBox.Name = "FilenameTextBox";
|
||||
this.FilenameTextBox.ReadOnly = true;
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(341, 23);
|
||||
this.FilenameTextBox.TabIndex = 3;
|
||||
//
|
||||
// containerControl1
|
||||
//
|
||||
this.containerControl1.Controls.Add(this.RuleListBox);
|
||||
this.containerControl1.Location = new System.Drawing.Point(6, 100);
|
||||
this.containerControl1.Controls.Add(this.RuleRichTextBox);
|
||||
this.containerControl1.Location = new System.Drawing.Point(6, 81);
|
||||
this.containerControl1.Name = "containerControl1";
|
||||
this.containerControl1.Size = new System.Drawing.Size(328, 157);
|
||||
this.containerControl1.TabIndex = 10;
|
||||
this.containerControl1.Padding = new Padding(0);
|
||||
this.containerControl1.Size = new System.Drawing.Size(419, 221);
|
||||
this.containerControl1.TabIndex = 4;
|
||||
this.containerControl1.Text = "containerControl1";
|
||||
//
|
||||
// RuleRichTextBox
|
||||
//
|
||||
this.RuleRichTextBox.DetectUrls = false;
|
||||
this.RuleRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.RuleRichTextBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.RuleRichTextBox.Name = "RuleRichTextBox";
|
||||
this.RuleRichTextBox.Size = new System.Drawing.Size(419, 221);
|
||||
this.RuleRichTextBox.TabIndex = 0;
|
||||
this.RuleRichTextBox.Text = "";
|
||||
this.RuleRichTextBox.WordWrap = false;
|
||||
//
|
||||
// ProcessGroupBox
|
||||
//
|
||||
this.ProcessGroupBox.Controls.Add(this.SelectButton);
|
||||
this.ProcessGroupBox.Controls.Add(this.ScanButton);
|
||||
this.ProcessGroupBox.Controls.Add(this.ValidationButton);
|
||||
this.ProcessGroupBox.Location = new System.Drawing.Point(6, 295);
|
||||
this.ProcessGroupBox.Name = "ProcessGroupBox";
|
||||
this.ProcessGroupBox.Size = new System.Drawing.Size(419, 44);
|
||||
this.ProcessGroupBox.TabIndex = 5;
|
||||
this.ProcessGroupBox.TabStop = false;
|
||||
//
|
||||
// SelectButton
|
||||
//
|
||||
this.SelectButton.Location = new System.Drawing.Point(6, 13);
|
||||
this.SelectButton.Name = "SelectButton";
|
||||
this.SelectButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.SelectButton.TabIndex = 0;
|
||||
this.SelectButton.Text = "Select";
|
||||
this.SelectButton.UseVisualStyleBackColor = true;
|
||||
this.SelectButton.Click += new System.EventHandler(this.SelectButton_Click);
|
||||
//
|
||||
// ScanButton
|
||||
//
|
||||
this.ScanButton.Location = new System.Drawing.Point(87, 13);
|
||||
this.ScanButton.Name = "ScanButton";
|
||||
this.ScanButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ScanButton.TabIndex = 1;
|
||||
this.ScanButton.Text = "Scan";
|
||||
this.ScanButton.UseVisualStyleBackColor = true;
|
||||
this.ScanButton.Click += new System.EventHandler(this.ScanButton_Click);
|
||||
//
|
||||
// ValidationButton
|
||||
//
|
||||
this.ValidationButton.Location = new System.Drawing.Point(338, 13);
|
||||
this.ValidationButton.Name = "ValidationButton";
|
||||
this.ValidationButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ValidationButton.TabIndex = 2;
|
||||
this.ValidationButton.Text = "Validation";
|
||||
this.ValidationButton.UseVisualStyleBackColor = true;
|
||||
this.ValidationButton.Click += new System.EventHandler(this.ValidationButton_Click);
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
this.ControlButton.Location = new System.Drawing.Point(344, 345);
|
||||
this.ControlButton.Name = "ControlButton";
|
||||
this.ControlButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ControlButton.TabIndex = 6;
|
||||
this.ControlButton.Text = "Save";
|
||||
this.ControlButton.UseVisualStyleBackColor = true;
|
||||
this.ControlButton.Click += new System.EventHandler(this.ControlButton_Click);
|
||||
//
|
||||
// Process
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(364, 397);
|
||||
this.Controls.Add(this.ControlButton);
|
||||
this.ClientSize = new System.Drawing.Size(455, 388);
|
||||
this.Controls.Add(this.ConfigurationGroupBox);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte) (134)));
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "Process";
|
||||
this.Padding = new System.Windows.Forms.Padding(12, 5, 12, 5);
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Create Process Mode";
|
||||
this.Load += new System.EventHandler(this.ModeForm_Load);
|
||||
this.ConfigurationGroupBox.ResumeLayout(false);
|
||||
this.ConfigurationGroupBox.PerformLayout();
|
||||
this.ProcessGroupBox.ResumeLayout(false);
|
||||
this.ProcessGroupBox.PerformLayout();
|
||||
this.contextMenuStrip.ResumeLayout(false);
|
||||
this.containerControl1.ResumeLayout(false);
|
||||
this.ProcessGroupBox.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button ScanButton;
|
||||
private System.Windows.Forms.ContainerControl containerControl1;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
|
||||
private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
|
||||
public System.Windows.Forms.GroupBox ConfigurationGroupBox;
|
||||
private System.Windows.Forms.Label RemarkLabel;
|
||||
private System.Windows.Forms.GroupBox ProcessGroupBox;
|
||||
private System.Windows.Forms.ListBox RuleListBox;
|
||||
private System.Windows.Forms.TextBox RemarkTextBox;
|
||||
private System.Windows.Forms.TextBox ProcessNameTextBox;
|
||||
private System.Windows.Forms.Button AddButton;
|
||||
private System.Windows.Forms.Button ScanButton;
|
||||
private System.Windows.Forms.Button SelectButton;
|
||||
public System.Windows.Forms.Button ControlButton;
|
||||
private System.Windows.Forms.Label FilenameLabel;
|
||||
private System.Windows.Forms.TextBox FilenameTextBox;
|
||||
private System.Windows.Forms.CheckBox UseCustomFilenameBox;
|
||||
private RichTextBox RuleRichTextBox;
|
||||
private Button ValidationButton;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
@@ -31,103 +33,48 @@ namespace Netch.Forms.Mode
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
|
||||
_mode = mode;
|
||||
if (mode != null)
|
||||
}
|
||||
|
||||
#region Model
|
||||
|
||||
public IEnumerable<string> Rules => RuleRichTextBox.Lines;
|
||||
|
||||
private void RuleAdd(string value)
|
||||
{
|
||||
RuleRichTextBox.AppendText($"{value}\n");
|
||||
}
|
||||
|
||||
private void RuleAddRange(IEnumerable<string> value)
|
||||
{
|
||||
foreach (string s in value)
|
||||
{
|
||||
RuleAdd(s);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void ModeForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (_mode != null)
|
||||
{
|
||||
Text = "Edit Process Mode";
|
||||
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Enabled = false;
|
||||
|
||||
RemarkTextBox.Text = mode.Remark;
|
||||
FilenameTextBox.Text = mode.RelativePath;
|
||||
RuleListBox.Items.AddRange(mode.Rule.ToArray());
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
RuleAddRange(_mode.Rule);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否被编辑过
|
||||
/// </summary>
|
||||
public bool Edited { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扫描目录
|
||||
/// </summary>
|
||||
/// <param name="DirName">路径</param>
|
||||
public void ScanDirectory(string DirName)
|
||||
{
|
||||
try
|
||||
{
|
||||
RuleListBox.Items.AddRange(Directory.GetFiles(DirName, "*.exe", SearchOption.AllDirectories)
|
||||
.Select(f => Path.GetFileName(f))
|
||||
.ToArray());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public void ModeForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
i18N.Translate(contextMenuStrip);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// listBox右键菜单
|
||||
/// </summary>
|
||||
private void RuleListBox_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
RuleListBox.SelectedIndex = RuleListBox.IndexFromPoint(e.X, e.Y);
|
||||
if (RuleListBox.SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
if (e.Button == MouseButtons.Right)
|
||||
contextMenuStrip.Show(RuleListBox, e.Location);
|
||||
}
|
||||
|
||||
private void deleteRule_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (RuleListBox.SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
RuleListBox.Items.RemoveAt(RuleListBox.SelectedIndex);
|
||||
Edited = true;
|
||||
}
|
||||
|
||||
private async void AddButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please enter an process name (xxx.exe)"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NFController.CheckCppRegex(ProcessNameTextBox.Text))
|
||||
{
|
||||
MessageBoxX.Show("Rule does not conform to C++ regular expression syntax");
|
||||
return;
|
||||
}
|
||||
|
||||
var process = ProcessNameTextBox.Text;
|
||||
|
||||
if (!RuleListBox.Items.Contains(process))
|
||||
RuleListBox.Items.Add(process);
|
||||
|
||||
Edited = true;
|
||||
RuleListBox.SelectedIndex = RuleListBox.Items.IndexOf(process);
|
||||
ProcessNameTextBox.Text = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
private void ScanButton_Click(object sender, EventArgs e)
|
||||
private void SelectButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog
|
||||
{
|
||||
IsFolderPicker = true,
|
||||
Multiselect = false,
|
||||
Multiselect = true,
|
||||
Title = i18N.Translate("Select a folder"),
|
||||
AddToMostRecentlyUsedList = false,
|
||||
EnsurePathExists = true,
|
||||
@@ -136,14 +83,20 @@ namespace Netch.Forms.Mode
|
||||
|
||||
if (dialog.ShowDialog(Handle) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
ScanDirectory(dialog.FileName);
|
||||
MessageBoxX.Show(i18N.Translate("Scan completed"));
|
||||
foreach (string p in dialog.FileNames)
|
||||
{
|
||||
string path = p;
|
||||
if (!path.EndsWith(@"\"))
|
||||
path += @"\";
|
||||
|
||||
RuleAdd($"^{path.ToRegexString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (RuleListBox.Items.Count == 0)
|
||||
if (!RuleRichTextBox.Lines.Any())
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Unable to add empty rule"));
|
||||
return;
|
||||
@@ -165,16 +118,14 @@ namespace Netch.Forms.Mode
|
||||
{
|
||||
_mode.Remark = RemarkTextBox.Text;
|
||||
_mode.Rule.Clear();
|
||||
_mode.Rule.AddRange(RuleListBox.Items.Cast<string>());
|
||||
_mode.Rule.AddRange(RuleRichTextBox.Lines);
|
||||
|
||||
_mode.WriteFile();
|
||||
Global.MainForm.LoadModes();
|
||||
Edited = false;
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var relativePath = $"Custom\\{FilenameTextBox.Text}.txt";
|
||||
var relativePath = FilenameTextBox.Text;
|
||||
var fullName = ModeHelper.GetFullPath(relativePath);
|
||||
if (File.Exists(fullName))
|
||||
{
|
||||
@@ -189,25 +140,73 @@ namespace Netch.Forms.Mode
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(RuleListBox.Items.Cast<string>());
|
||||
mode.Rule.AddRange(RuleRichTextBox.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
ModeHelper.Add(mode);
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private async void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
private void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (!UseCustomFilenameBox.Checked)
|
||||
FilenameTextBox.Text = FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text);
|
||||
}));
|
||||
}
|
||||
|
||||
private void ScanButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog
|
||||
{
|
||||
IsFolderPicker = true,
|
||||
Multiselect = false,
|
||||
Title = i18N.Translate("Select a folder"),
|
||||
AddToMostRecentlyUsedList = false,
|
||||
EnsurePathExists = true,
|
||||
NavigateToShortcut = true
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog(Handle) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
var path = dialog.FileName;
|
||||
var list = new List<string>();
|
||||
const uint maxCount = 50;
|
||||
try
|
||||
{
|
||||
FilenameTextBox.Text = ModeEditorUtils.ToSafeFileName(RemarkTextBox.Text);
|
||||
ScanDirectory(path, list);
|
||||
}
|
||||
});
|
||||
catch
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate($"The number of executable files in the \"{path}\" directory is greater than {maxCount}"),
|
||||
LogLevel.WARNING);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
RuleAddRange(list);
|
||||
}
|
||||
}
|
||||
|
||||
private void ScanDirectory(string directory, List<string> list, uint maxCount = 30)
|
||||
{
|
||||
foreach (string dir in Directory.GetDirectories(directory))
|
||||
ScanDirectory(dir, list, maxCount);
|
||||
|
||||
list.AddRange(Directory.GetFiles(directory).Select(Path.GetFileName).Where(s => s.EndsWith(".exe")).Select(s => s.ToRegexString()));
|
||||
|
||||
if (maxCount != 0 && list.Count > maxCount)
|
||||
throw new Exception("The number of results is greater than maxCount");
|
||||
}
|
||||
|
||||
private void ValidationButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (NFController.CheckRules(Rules, out var results))
|
||||
MessageBoxX.Show(NFController.GenerateInvalidRulesMessage(results), LogLevel.WARNING);
|
||||
else
|
||||
MessageBoxX.Show("Fine");
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Netch/Forms/Mode/Route.Designer.cs
generated
@@ -35,7 +35,6 @@ namespace Netch.Forms.Mode
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.comboBox1 = new System.Windows.Forms.ComboBox();
|
||||
this.UseCustomFilenameBox = new System.Windows.Forms.CheckBox();
|
||||
this.FilenameLabel = new System.Windows.Forms.Label();
|
||||
this.FilenameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ActionLabel = new System.Windows.Forms.Label();
|
||||
@@ -54,7 +53,6 @@ namespace Netch.Forms.Mode
|
||||
// ConfigurationGroupBox
|
||||
//
|
||||
this.ConfigurationGroupBox.Controls.Add(this.comboBox1);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.UseCustomFilenameBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.FilenameLabel);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.FilenameTextBox);
|
||||
this.ConfigurationGroupBox.Controls.Add(this.ActionLabel);
|
||||
@@ -77,16 +75,6 @@ namespace Netch.Forms.Mode
|
||||
this.comboBox1.Size = new System.Drawing.Size(138, 20);
|
||||
this.comboBox1.TabIndex = 11;
|
||||
//
|
||||
// UseCustomFilenameBox
|
||||
//
|
||||
this.UseCustomFilenameBox.AutoSize = true;
|
||||
this.UseCustomFilenameBox.Location = new System.Drawing.Point(84, 100);
|
||||
this.UseCustomFilenameBox.Name = "UseCustomFilenameBox";
|
||||
this.UseCustomFilenameBox.Size = new System.Drawing.Size(138, 16);
|
||||
this.UseCustomFilenameBox.TabIndex = 9;
|
||||
this.UseCustomFilenameBox.Text = "Use Custom Filename";
|
||||
this.UseCustomFilenameBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FilenameLabel
|
||||
//
|
||||
this.FilenameLabel.AutoSize = true;
|
||||
@@ -98,9 +86,9 @@ namespace Netch.Forms.Mode
|
||||
//
|
||||
// FilenameTextBox
|
||||
//
|
||||
this.FilenameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.UseCustomFilenameBox, "Checked", true));
|
||||
this.FilenameTextBox.Location = new System.Drawing.Point(84, 76);
|
||||
this.FilenameTextBox.Name = "FilenameTextBox";
|
||||
this.FilenameTextBox.ReadOnly = true;
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(250, 21);
|
||||
this.FilenameTextBox.TabIndex = 5;
|
||||
//
|
||||
@@ -133,9 +121,9 @@ namespace Netch.Forms.Mode
|
||||
// containerControl1
|
||||
//
|
||||
this.containerControl1.Controls.Add(this.richTextBox1);
|
||||
this.containerControl1.Location = new System.Drawing.Point(6, 125);
|
||||
this.containerControl1.Location = new System.Drawing.Point(6, 103);
|
||||
this.containerControl1.Name = "containerControl1";
|
||||
this.containerControl1.Size = new System.Drawing.Size(328, 224);
|
||||
this.containerControl1.Size = new System.Drawing.Size(328, 246);
|
||||
this.containerControl1.TabIndex = 10;
|
||||
this.containerControl1.Text = "containerControl1";
|
||||
//
|
||||
@@ -144,13 +132,14 @@ namespace Netch.Forms.Mode
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.Size = new System.Drawing.Size(328, 224);
|
||||
this.richTextBox1.Size = new System.Drawing.Size(328, 246);
|
||||
this.richTextBox1.TabIndex = 0;
|
||||
this.richTextBox1.Text = "";
|
||||
//
|
||||
// contextMenuStrip
|
||||
//
|
||||
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.DeleteToolStripMenuItem});
|
||||
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.DeleteToolStripMenuItem});
|
||||
this.contextMenuStrip.Name = "contextMenuStrip";
|
||||
this.contextMenuStrip.Size = new System.Drawing.Size(114, 26);
|
||||
//
|
||||
@@ -186,6 +175,7 @@ namespace Netch.Forms.Mode
|
||||
this.containerControl1.ResumeLayout(false);
|
||||
this.contextMenuStrip.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
public System.Windows.Forms.GroupBox ConfigurationGroupBox;
|
||||
@@ -198,7 +188,6 @@ namespace Netch.Forms.Mode
|
||||
private System.Windows.Forms.Label RemarkLabel;
|
||||
private System.Windows.Forms.TextBox RemarkTextBox;
|
||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||
private System.Windows.Forms.CheckBox UseCustomFilenameBox;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
@@ -44,8 +43,6 @@ namespace Netch.Forms.Mode
|
||||
comboBox1.DataSource = _items;
|
||||
comboBox1.ValueMember = "Value";
|
||||
comboBox1.DisplayMember = "Text";
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
}
|
||||
|
||||
private void Route_Load(object sender, EventArgs e)
|
||||
@@ -55,13 +52,13 @@ namespace Netch.Forms.Mode
|
||||
Text = "Edit Route Table Rule";
|
||||
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Enabled = false;
|
||||
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
richTextBox1.Lines = _mode.Rule.ToArray();
|
||||
}
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
@@ -86,12 +83,11 @@ namespace Netch.Forms.Mode
|
||||
_mode.Type = (int) comboBox1.SelectedValue;
|
||||
|
||||
_mode.WriteFile();
|
||||
Global.MainForm.LoadModes();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
}
|
||||
else
|
||||
{
|
||||
var relativePath = $"Custom\\{FilenameTextBox.Text}.txt";
|
||||
var relativePath = FilenameTextBox.Text;
|
||||
var fullName = ModeHelper.GetFullPath(relativePath);
|
||||
if (File.Exists(fullName))
|
||||
{
|
||||
@@ -108,22 +104,18 @@ namespace Netch.Forms.Mode
|
||||
mode.Rule.AddRange(richTextBox1.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
ModeHelper.Add(mode);
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private async void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
private void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (!UseCustomFilenameBox.Checked)
|
||||
{
|
||||
FilenameTextBox.Text = ModeEditorUtils.ToSafeFileName(RemarkTextBox.Text);
|
||||
}
|
||||
});
|
||||
FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
341
Netch/Forms/SettingForm.Designer.cs
generated
@@ -33,9 +33,6 @@ namespace Netch.Forms
|
||||
{
|
||||
this.TabControl = new System.Windows.Forms.TabControl();
|
||||
this.GeneralTabPage = new System.Windows.Forms.TabPage();
|
||||
this.ServerPingTypeLabel = new System.Windows.Forms.Label();
|
||||
this.TCPingRadioBtn = new System.Windows.Forms.RadioButton();
|
||||
this.ICMPingRadioBtn = new System.Windows.Forms.RadioButton();
|
||||
this.PortGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.Socks5PortLabel = new System.Windows.Forms.Label();
|
||||
this.Socks5PortTextBox = new System.Windows.Forms.TextBox();
|
||||
@@ -44,14 +41,16 @@ namespace Netch.Forms
|
||||
this.RedirectorLabel = new System.Windows.Forms.Label();
|
||||
this.RedirectorTextBox = new System.Windows.Forms.TextBox();
|
||||
this.AllowDevicesCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.BootShadowsocksFromDLLCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ResolveServerHostnameCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ServerPingTypeLabel = new System.Windows.Forms.Label();
|
||||
this.ICMPingRadioBtn = new System.Windows.Forms.RadioButton();
|
||||
this.TCPingRadioBtn = new System.Windows.Forms.RadioButton();
|
||||
this.ProfileCountLabel = new System.Windows.Forms.Label();
|
||||
this.ProfileCountTextBox = new System.Windows.Forms.TextBox();
|
||||
this.StartedPingLabel = new System.Windows.Forms.Label();
|
||||
this.DetectionTickLabel = new System.Windows.Forms.Label();
|
||||
this.StartedPingIntervalTextBox = new System.Windows.Forms.TextBox();
|
||||
this.DetectionTickTextBox = new System.Windows.Forms.TextBox();
|
||||
this.StartedPingLabel = new System.Windows.Forms.Label();
|
||||
this.StartedPingIntervalTextBox = new System.Windows.Forms.TextBox();
|
||||
this.STUNServerLabel = new System.Windows.Forms.Label();
|
||||
this.STUN_ServerComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.AclLabel = new System.Windows.Forms.Label();
|
||||
@@ -59,12 +58,17 @@ namespace Netch.Forms
|
||||
this.LanguageLabel = new System.Windows.Forms.Label();
|
||||
this.LanguageComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.NFTabPage = new System.Windows.Forms.TabPage();
|
||||
this.ProcessProxyProtocolComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.ModifySystemDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.ProcessProxyProtocolLabel = new System.Windows.Forms.Label();
|
||||
this.ModifiedDNSLabel = new System.Windows.Forms.Label();
|
||||
this.ModifiedDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ProcessProxyProtocolComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.DNSRedirectorCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.RDRDNSLabel = new System.Windows.Forms.Label();
|
||||
this.RDRDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ICMPRedirectorCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.RDRICMPLabel = new System.Windows.Forms.Label();
|
||||
this.ModifiedICMPTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RedirectorSSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ChildProcessHandleCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.TAPTabPage = new System.Windows.Forms.TabPage();
|
||||
this.TUNTAPGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.TUNTAPAddressLabel = new System.Windows.Forms.Label();
|
||||
@@ -80,8 +84,8 @@ namespace Netch.Forms
|
||||
this.UseFakeDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.GlobalBypassIPsButton = new System.Windows.Forms.Button();
|
||||
this.v2rayTabPage = new System.Windows.Forms.TabPage();
|
||||
this.TLSAllowInsecureCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.XrayConeCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.TLSAllowInsecureCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UseMuxCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.KCPGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.mtuLabel = new System.Windows.Forms.Label();
|
||||
@@ -119,6 +123,7 @@ namespace Netch.Forms
|
||||
this.GeneralTabPage.SuspendLayout();
|
||||
this.PortGroupBox.SuspendLayout();
|
||||
this.NFTabPage.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.TAPTabPage.SuspendLayout();
|
||||
this.TUNTAPGroupBox.SuspendLayout();
|
||||
this.v2rayTabPage.SuspendLayout();
|
||||
@@ -146,18 +151,17 @@ namespace Netch.Forms
|
||||
// GeneralTabPage
|
||||
//
|
||||
this.GeneralTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.GeneralTabPage.Controls.Add(this.ServerPingTypeLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.TCPingRadioBtn);
|
||||
this.GeneralTabPage.Controls.Add(this.ICMPingRadioBtn);
|
||||
this.GeneralTabPage.Controls.Add(this.PortGroupBox);
|
||||
this.GeneralTabPage.Controls.Add(this.BootShadowsocksFromDLLCheckBox);
|
||||
this.GeneralTabPage.Controls.Add(this.ResolveServerHostnameCheckBox);
|
||||
this.GeneralTabPage.Controls.Add(this.ServerPingTypeLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.ICMPingRadioBtn);
|
||||
this.GeneralTabPage.Controls.Add(this.TCPingRadioBtn);
|
||||
this.GeneralTabPage.Controls.Add(this.ProfileCountLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.ProfileCountTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.StartedPingLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.DetectionTickLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.StartedPingIntervalTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.DetectionTickTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.StartedPingLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.StartedPingIntervalTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.STUNServerLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.STUN_ServerComboBox);
|
||||
this.GeneralTabPage.Controls.Add(this.AclLabel);
|
||||
@@ -171,37 +175,6 @@ namespace Netch.Forms
|
||||
this.GeneralTabPage.TabIndex = 0;
|
||||
this.GeneralTabPage.Text = "General";
|
||||
//
|
||||
// ServerPingTypeLabel
|
||||
//
|
||||
this.ServerPingTypeLabel.AutoSize = true;
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 66);
|
||||
this.ServerPingTypeLabel.Name = "ServerPingTypeLabel";
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(89, 12);
|
||||
this.ServerPingTypeLabel.TabIndex = 16;
|
||||
this.ServerPingTypeLabel.Text = "ServerPingType";
|
||||
//
|
||||
// TCPingRadioBtn
|
||||
//
|
||||
this.TCPingRadioBtn.AutoSize = true;
|
||||
this.TCPingRadioBtn.Location = new System.Drawing.Point(332, 85);
|
||||
this.TCPingRadioBtn.Name = "TCPingRadioBtn";
|
||||
this.TCPingRadioBtn.Size = new System.Drawing.Size(59, 16);
|
||||
this.TCPingRadioBtn.TabIndex = 15;
|
||||
this.TCPingRadioBtn.TabStop = true;
|
||||
this.TCPingRadioBtn.Text = "TCPing";
|
||||
this.TCPingRadioBtn.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ICMPingRadioBtn
|
||||
//
|
||||
this.ICMPingRadioBtn.AutoSize = true;
|
||||
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 85);
|
||||
this.ICMPingRadioBtn.Name = "ICMPingRadioBtn";
|
||||
this.ICMPingRadioBtn.Size = new System.Drawing.Size(65, 16);
|
||||
this.ICMPingRadioBtn.TabIndex = 14;
|
||||
this.ICMPingRadioBtn.TabStop = true;
|
||||
this.ICMPingRadioBtn.Text = "ICMPing";
|
||||
this.ICMPingRadioBtn.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// PortGroupBox
|
||||
//
|
||||
this.PortGroupBox.Controls.Add(this.Socks5PortLabel);
|
||||
@@ -280,33 +253,54 @@ namespace Netch.Forms
|
||||
this.AllowDevicesCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.AllowDevicesCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// BootShadowsocksFromDLLCheckBox
|
||||
//
|
||||
this.BootShadowsocksFromDLLCheckBox.AutoSize = true;
|
||||
this.BootShadowsocksFromDLLCheckBox.Location = new System.Drawing.Point(267, 15);
|
||||
this.BootShadowsocksFromDLLCheckBox.Name = "BootShadowsocksFromDLLCheckBox";
|
||||
this.BootShadowsocksFromDLLCheckBox.Size = new System.Drawing.Size(60, 16);
|
||||
this.BootShadowsocksFromDLLCheckBox.TabIndex = 1;
|
||||
this.BootShadowsocksFromDLLCheckBox.Text = "SS DLL";
|
||||
this.BootShadowsocksFromDLLCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ResolveServerHostnameCheckBox
|
||||
//
|
||||
this.ResolveServerHostnameCheckBox.AutoSize = true;
|
||||
this.ResolveServerHostnameCheckBox.Location = new System.Drawing.Point(267, 37);
|
||||
this.ResolveServerHostnameCheckBox.Location = new System.Drawing.Point(267, 15);
|
||||
this.ResolveServerHostnameCheckBox.Name = "ResolveServerHostnameCheckBox";
|
||||
this.ResolveServerHostnameCheckBox.Size = new System.Drawing.Size(162, 16);
|
||||
this.ResolveServerHostnameCheckBox.TabIndex = 2;
|
||||
this.ResolveServerHostnameCheckBox.TabIndex = 1;
|
||||
this.ResolveServerHostnameCheckBox.Text = "Resolve Server Hostname";
|
||||
this.ResolveServerHostnameCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ServerPingTypeLabel
|
||||
//
|
||||
this.ServerPingTypeLabel.AutoSize = true;
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 44);
|
||||
this.ServerPingTypeLabel.Name = "ServerPingTypeLabel";
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(89, 12);
|
||||
this.ServerPingTypeLabel.TabIndex = 2;
|
||||
this.ServerPingTypeLabel.Text = "ServerPingType";
|
||||
//
|
||||
// ICMPingRadioBtn
|
||||
//
|
||||
this.ICMPingRadioBtn.AutoSize = true;
|
||||
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 63);
|
||||
this.ICMPingRadioBtn.Name = "ICMPingRadioBtn";
|
||||
this.ICMPingRadioBtn.Size = new System.Drawing.Size(65, 16);
|
||||
this.ICMPingRadioBtn.TabIndex = 3;
|
||||
this.ICMPingRadioBtn.TabStop = true;
|
||||
this.ICMPingRadioBtn.Text = "ICMPing";
|
||||
this.ICMPingRadioBtn.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// TCPingRadioBtn
|
||||
//
|
||||
this.TCPingRadioBtn.AutoSize = true;
|
||||
this.TCPingRadioBtn.Location = new System.Drawing.Point(332, 63);
|
||||
this.TCPingRadioBtn.Name = "TCPingRadioBtn";
|
||||
this.TCPingRadioBtn.Size = new System.Drawing.Size(59, 16);
|
||||
this.TCPingRadioBtn.TabIndex = 4;
|
||||
this.TCPingRadioBtn.TabStop = true;
|
||||
this.TCPingRadioBtn.Text = "TCPing";
|
||||
this.TCPingRadioBtn.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ProfileCountLabel
|
||||
//
|
||||
this.ProfileCountLabel.AutoSize = true;
|
||||
this.ProfileCountLabel.Location = new System.Drawing.Point(12, 160);
|
||||
this.ProfileCountLabel.Name = "ProfileCountLabel";
|
||||
this.ProfileCountLabel.Size = new System.Drawing.Size(77, 12);
|
||||
this.ProfileCountLabel.TabIndex = 3;
|
||||
this.ProfileCountLabel.TabIndex = 5;
|
||||
this.ProfileCountLabel.Text = "ProfileCount";
|
||||
//
|
||||
// ProfileCountTextBox
|
||||
@@ -314,50 +308,50 @@ namespace Netch.Forms
|
||||
this.ProfileCountTextBox.Location = new System.Drawing.Point(120, 157);
|
||||
this.ProfileCountTextBox.Name = "ProfileCountTextBox";
|
||||
this.ProfileCountTextBox.Size = new System.Drawing.Size(90, 21);
|
||||
this.ProfileCountTextBox.TabIndex = 4;
|
||||
this.ProfileCountTextBox.TabIndex = 6;
|
||||
this.ProfileCountTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// StartedPingLabel
|
||||
//
|
||||
this.StartedPingLabel.AutoSize = true;
|
||||
this.StartedPingLabel.Location = new System.Drawing.Point(12, 187);
|
||||
this.StartedPingLabel.Name = "StartedPingLabel";
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(137, 12);
|
||||
this.StartedPingLabel.TabIndex = 5;
|
||||
this.StartedPingLabel.Text = "Delay test after start";
|
||||
//
|
||||
// DetectionTickLabel
|
||||
//
|
||||
this.DetectionTickLabel.AutoSize = true;
|
||||
this.DetectionTickLabel.Location = new System.Drawing.Point(225, 160);
|
||||
this.DetectionTickLabel.Name = "DetectionTickLabel";
|
||||
this.DetectionTickLabel.Size = new System.Drawing.Size(119, 12);
|
||||
this.DetectionTickLabel.TabIndex = 6;
|
||||
this.DetectionTickLabel.TabIndex = 7;
|
||||
this.DetectionTickLabel.Text = "Detection Tick(sec)";
|
||||
//
|
||||
// StartedPingIntervalTextBox
|
||||
//
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(177, 184);
|
||||
this.StartedPingIntervalTextBox.Name = "StartedPingIntervalTextBox";
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(68, 21);
|
||||
this.StartedPingIntervalTextBox.TabIndex = 7;
|
||||
this.StartedPingIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// DetectionTickTextBox
|
||||
//
|
||||
this.DetectionTickTextBox.Location = new System.Drawing.Point(366, 157);
|
||||
this.DetectionTickTextBox.Name = "DetectionTickTextBox";
|
||||
this.DetectionTickTextBox.Size = new System.Drawing.Size(68, 21);
|
||||
this.DetectionTickTextBox.TabIndex = 7;
|
||||
this.DetectionTickTextBox.TabIndex = 8;
|
||||
this.DetectionTickTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// StartedPingLabel
|
||||
//
|
||||
this.StartedPingLabel.AutoSize = true;
|
||||
this.StartedPingLabel.Location = new System.Drawing.Point(12, 187);
|
||||
this.StartedPingLabel.Name = "StartedPingLabel";
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(137, 12);
|
||||
this.StartedPingLabel.TabIndex = 9;
|
||||
this.StartedPingLabel.Text = "Delay test after start";
|
||||
//
|
||||
// StartedPingIntervalTextBox
|
||||
//
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(177, 184);
|
||||
this.StartedPingIntervalTextBox.Name = "StartedPingIntervalTextBox";
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(68, 21);
|
||||
this.StartedPingIntervalTextBox.TabIndex = 10;
|
||||
this.StartedPingIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// STUNServerLabel
|
||||
//
|
||||
this.STUNServerLabel.AutoSize = true;
|
||||
this.STUNServerLabel.Location = new System.Drawing.Point(12, 216);
|
||||
this.STUNServerLabel.Name = "STUNServerLabel";
|
||||
this.STUNServerLabel.Size = new System.Drawing.Size(71, 12);
|
||||
this.STUNServerLabel.TabIndex = 8;
|
||||
this.STUNServerLabel.TabIndex = 11;
|
||||
this.STUNServerLabel.Text = "STUN Server";
|
||||
//
|
||||
// STUN_ServerComboBox
|
||||
@@ -366,7 +360,7 @@ namespace Netch.Forms
|
||||
this.STUN_ServerComboBox.Location = new System.Drawing.Point(120, 213);
|
||||
this.STUN_ServerComboBox.Name = "STUN_ServerComboBox";
|
||||
this.STUN_ServerComboBox.Size = new System.Drawing.Size(314, 20);
|
||||
this.STUN_ServerComboBox.TabIndex = 9;
|
||||
this.STUN_ServerComboBox.TabIndex = 12;
|
||||
//
|
||||
// AclLabel
|
||||
//
|
||||
@@ -374,7 +368,7 @@ namespace Netch.Forms
|
||||
this.AclLabel.Location = new System.Drawing.Point(12, 248);
|
||||
this.AclLabel.Name = "AclLabel";
|
||||
this.AclLabel.Size = new System.Drawing.Size(65, 12);
|
||||
this.AclLabel.TabIndex = 10;
|
||||
this.AclLabel.TabIndex = 13;
|
||||
this.AclLabel.Text = "Custom ACL";
|
||||
//
|
||||
// AclAddrTextBox
|
||||
@@ -382,7 +376,7 @@ namespace Netch.Forms
|
||||
this.AclAddrTextBox.Location = new System.Drawing.Point(120, 245);
|
||||
this.AclAddrTextBox.Name = "AclAddrTextBox";
|
||||
this.AclAddrTextBox.Size = new System.Drawing.Size(314, 21);
|
||||
this.AclAddrTextBox.TabIndex = 11;
|
||||
this.AclAddrTextBox.TabIndex = 14;
|
||||
this.AclAddrTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// LanguageLabel
|
||||
@@ -391,7 +385,7 @@ namespace Netch.Forms
|
||||
this.LanguageLabel.Location = new System.Drawing.Point(12, 277);
|
||||
this.LanguageLabel.Name = "LanguageLabel";
|
||||
this.LanguageLabel.Size = new System.Drawing.Size(53, 12);
|
||||
this.LanguageLabel.TabIndex = 12;
|
||||
this.LanguageLabel.TabIndex = 15;
|
||||
this.LanguageLabel.Text = "Language";
|
||||
//
|
||||
// LanguageComboBox
|
||||
@@ -401,17 +395,14 @@ namespace Netch.Forms
|
||||
this.LanguageComboBox.Location = new System.Drawing.Point(120, 274);
|
||||
this.LanguageComboBox.Name = "LanguageComboBox";
|
||||
this.LanguageComboBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.LanguageComboBox.TabIndex = 13;
|
||||
this.LanguageComboBox.TabIndex = 16;
|
||||
//
|
||||
// NFTabPage
|
||||
//
|
||||
this.NFTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.NFTabPage.Controls.Add(this.ModifySystemDNSCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.ModifiedDNSLabel);
|
||||
this.NFTabPage.Controls.Add(this.ModifiedDNSTextBox);
|
||||
this.NFTabPage.Controls.Add(this.groupBox1);
|
||||
this.NFTabPage.Controls.Add(this.RedirectorSSCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.ProcessProxyProtocolLabel);
|
||||
this.NFTabPage.Controls.Add(this.ProcessProxyProtocolComboBox);
|
||||
this.NFTabPage.Controls.Add(this.ChildProcessHandleCheckBox);
|
||||
this.NFTabPage.Location = new System.Drawing.Point(4, 25);
|
||||
this.NFTabPage.Name = "NFTabPage";
|
||||
this.NFTabPage.Padding = new System.Windows.Forms.Padding(3);
|
||||
@@ -419,62 +410,116 @@ namespace Netch.Forms
|
||||
this.NFTabPage.TabIndex = 1;
|
||||
this.NFTabPage.Text = "Process Mode";
|
||||
//
|
||||
// ProcessProxyProtocolComboBox
|
||||
// groupBox1
|
||||
//
|
||||
this.ProcessProxyProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ProcessProxyProtocolComboBox.FormattingEnabled = true;
|
||||
this.ProcessProxyProtocolComboBox.Location = new System.Drawing.Point(167, 58);
|
||||
this.ProcessProxyProtocolComboBox.Name = "ProcessProxyProtocolComboBox";
|
||||
this.ProcessProxyProtocolComboBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.ProcessProxyProtocolComboBox.TabIndex = 3;
|
||||
//
|
||||
// ModifySystemDNSCheckBox
|
||||
//
|
||||
this.ModifySystemDNSCheckBox.AutoSize = true;
|
||||
this.ModifySystemDNSCheckBox.Location = new System.Drawing.Point(8, 16);
|
||||
this.ModifySystemDNSCheckBox.Name = "ModifySystemDNSCheckBox";
|
||||
this.ModifySystemDNSCheckBox.Size = new System.Drawing.Size(126, 16);
|
||||
this.ModifySystemDNSCheckBox.TabIndex = 0;
|
||||
this.ModifySystemDNSCheckBox.Text = "Modify System DNS";
|
||||
this.ModifySystemDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
this.groupBox1.Controls.Add(this.ProcessProxyProtocolLabel);
|
||||
this.groupBox1.Controls.Add(this.ProcessProxyProtocolComboBox);
|
||||
this.groupBox1.Controls.Add(this.DNSRedirectorCheckBox);
|
||||
this.groupBox1.Controls.Add(this.RDRDNSLabel);
|
||||
this.groupBox1.Controls.Add(this.RDRDNSTextBox);
|
||||
this.groupBox1.Controls.Add(this.ICMPRedirectorCheckBox);
|
||||
this.groupBox1.Controls.Add(this.RDRICMPLabel);
|
||||
this.groupBox1.Controls.Add(this.ModifiedICMPTextBox);
|
||||
this.groupBox1.Location = new System.Drawing.Point(5, 6);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(450, 117);
|
||||
this.groupBox1.TabIndex = 0;
|
||||
this.groupBox1.TabStop = false;
|
||||
//
|
||||
// ProcessProxyProtocolLabel
|
||||
//
|
||||
this.ProcessProxyProtocolLabel.AutoSize = true;
|
||||
this.ProcessProxyProtocolLabel.Location = new System.Drawing.Point(24, 61);
|
||||
this.ProcessProxyProtocolLabel.Location = new System.Drawing.Point(23, 21);
|
||||
this.ProcessProxyProtocolLabel.Name = "ProcessProxyProtocolLabel";
|
||||
this.ProcessProxyProtocolLabel.Size = new System.Drawing.Size(89, 12);
|
||||
this.ProcessProxyProtocolLabel.TabIndex = 2;
|
||||
this.ProcessProxyProtocolLabel.TabIndex = 0;
|
||||
this.ProcessProxyProtocolLabel.Text = "Proxy Protocol";
|
||||
//
|
||||
// ModifiedDNSLabel
|
||||
// ProcessProxyProtocolComboBox
|
||||
//
|
||||
this.ModifiedDNSLabel.AutoSize = true;
|
||||
this.ModifiedDNSLabel.Location = new System.Drawing.Point(223, 17);
|
||||
this.ModifiedDNSLabel.Name = "ModifiedDNSLabel";
|
||||
this.ModifiedDNSLabel.Size = new System.Drawing.Size(23, 12);
|
||||
this.ModifiedDNSLabel.TabIndex = 2;
|
||||
this.ModifiedDNSLabel.Text = "DNS";
|
||||
this.ProcessProxyProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ProcessProxyProtocolComboBox.FormattingEnabled = true;
|
||||
this.ProcessProxyProtocolComboBox.Location = new System.Drawing.Point(118, 16);
|
||||
this.ProcessProxyProtocolComboBox.Name = "ProcessProxyProtocolComboBox";
|
||||
this.ProcessProxyProtocolComboBox.Size = new System.Drawing.Size(191, 20);
|
||||
this.ProcessProxyProtocolComboBox.TabIndex = 1;
|
||||
//
|
||||
// ModifiedDNSTextBox
|
||||
// DNSRedirectorCheckBox
|
||||
//
|
||||
this.ModifiedDNSTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.ModifySystemDNSCheckBox, "Checked", true));
|
||||
this.ModifiedDNSTextBox.Location = new System.Drawing.Point(264, 14);
|
||||
this.ModifiedDNSTextBox.Name = "ModifiedDNSTextBox";
|
||||
this.ModifiedDNSTextBox.Size = new System.Drawing.Size(194, 21);
|
||||
this.ModifiedDNSTextBox.TabIndex = 1;
|
||||
this.ModifiedDNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.DNSRedirectorCheckBox.AutoSize = true;
|
||||
this.DNSRedirectorCheckBox.Location = new System.Drawing.Point(6, 51);
|
||||
this.DNSRedirectorCheckBox.Name = "DNSRedirectorCheckBox";
|
||||
this.DNSRedirectorCheckBox.Size = new System.Drawing.Size(108, 16);
|
||||
this.DNSRedirectorCheckBox.TabIndex = 2;
|
||||
this.DNSRedirectorCheckBox.Text = "DNS Redirector";
|
||||
this.DNSRedirectorCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// RDRDNSLabel
|
||||
//
|
||||
this.RDRDNSLabel.AutoSize = true;
|
||||
this.RDRDNSLabel.Location = new System.Drawing.Point(224, 52);
|
||||
this.RDRDNSLabel.Name = "RDRDNSLabel";
|
||||
this.RDRDNSLabel.Size = new System.Drawing.Size(23, 12);
|
||||
this.RDRDNSLabel.TabIndex = 3;
|
||||
this.RDRDNSLabel.Text = "DNS";
|
||||
//
|
||||
// RDRDNSTextBox
|
||||
//
|
||||
this.RDRDNSTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.DNSRedirectorCheckBox, "Checked", true));
|
||||
this.RDRDNSTextBox.Location = new System.Drawing.Point(253, 46);
|
||||
this.RDRDNSTextBox.Name = "RDRDNSTextBox";
|
||||
this.RDRDNSTextBox.Size = new System.Drawing.Size(191, 21);
|
||||
this.RDRDNSTextBox.TabIndex = 4;
|
||||
this.RDRDNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// ICMPRedirectorCheckBox
|
||||
//
|
||||
this.ICMPRedirectorCheckBox.AutoSize = true;
|
||||
this.ICMPRedirectorCheckBox.Location = new System.Drawing.Point(6, 81);
|
||||
this.ICMPRedirectorCheckBox.Name = "ICMPRedirectorCheckBox";
|
||||
this.ICMPRedirectorCheckBox.Size = new System.Drawing.Size(114, 16);
|
||||
this.ICMPRedirectorCheckBox.TabIndex = 5;
|
||||
this.ICMPRedirectorCheckBox.Text = "ICMP Redirector";
|
||||
this.ICMPRedirectorCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// RDRICMPLabel
|
||||
//
|
||||
this.RDRICMPLabel.AutoSize = true;
|
||||
this.RDRICMPLabel.Location = new System.Drawing.Point(218, 81);
|
||||
this.RDRICMPLabel.Name = "RDRICMPLabel";
|
||||
this.RDRICMPLabel.Size = new System.Drawing.Size(29, 12);
|
||||
this.RDRICMPLabel.TabIndex = 6;
|
||||
this.RDRICMPLabel.Text = "ICMP";
|
||||
//
|
||||
// ModifiedICMPTextBox
|
||||
//
|
||||
this.ModifiedICMPTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.ICMPRedirectorCheckBox, "Checked", true));
|
||||
this.ModifiedICMPTextBox.Location = new System.Drawing.Point(253, 78);
|
||||
this.ModifiedICMPTextBox.Name = "ModifiedICMPTextBox";
|
||||
this.ModifiedICMPTextBox.Size = new System.Drawing.Size(191, 21);
|
||||
this.ModifiedICMPTextBox.TabIndex = 7;
|
||||
this.ModifiedICMPTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// RedirectorSSCheckBox
|
||||
//
|
||||
this.RedirectorSSCheckBox.AutoSize = true;
|
||||
this.RedirectorSSCheckBox.Location = new System.Drawing.Point(8, 38);
|
||||
this.RedirectorSSCheckBox.Location = new System.Drawing.Point(11, 129);
|
||||
this.RedirectorSSCheckBox.Name = "RedirectorSSCheckBox";
|
||||
this.RedirectorSSCheckBox.Size = new System.Drawing.Size(102, 16);
|
||||
this.RedirectorSSCheckBox.TabIndex = 0;
|
||||
this.RedirectorSSCheckBox.TabIndex = 1;
|
||||
this.RedirectorSSCheckBox.Text = "Redirector SS";
|
||||
this.RedirectorSSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ChildProcessHandleCheckBox
|
||||
//
|
||||
this.ChildProcessHandleCheckBox.AutoSize = true;
|
||||
this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(11, 151);
|
||||
this.ChildProcessHandleCheckBox.Name = "ChildProcessHandleCheckBox";
|
||||
this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(144, 16);
|
||||
this.ChildProcessHandleCheckBox.TabIndex = 2;
|
||||
this.ChildProcessHandleCheckBox.Text = "Child Process Handle";
|
||||
this.ChildProcessHandleCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// TAPTabPage
|
||||
//
|
||||
this.TAPTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
@@ -621,8 +666,8 @@ namespace Netch.Forms
|
||||
// v2rayTabPage
|
||||
//
|
||||
this.v2rayTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.v2rayTabPage.Controls.Add(this.TLSAllowInsecureCheckBox);
|
||||
this.v2rayTabPage.Controls.Add(this.XrayConeCheckBox);
|
||||
this.v2rayTabPage.Controls.Add(this.TLSAllowInsecureCheckBox);
|
||||
this.v2rayTabPage.Controls.Add(this.UseMuxCheckBox);
|
||||
this.v2rayTabPage.Controls.Add(this.KCPGroupBox);
|
||||
this.v2rayTabPage.Location = new System.Drawing.Point(4, 25);
|
||||
@@ -632,33 +677,33 @@ namespace Netch.Forms
|
||||
this.v2rayTabPage.TabIndex = 3;
|
||||
this.v2rayTabPage.Text = "V2Ray";
|
||||
//
|
||||
// TLSAllowInsecureCheckBox
|
||||
//
|
||||
this.TLSAllowInsecureCheckBox.AutoSize = true;
|
||||
this.TLSAllowInsecureCheckBox.Location = new System.Drawing.Point(6, 42);
|
||||
this.TLSAllowInsecureCheckBox.Name = "TLSAllowInsecureCheckBox";
|
||||
this.TLSAllowInsecureCheckBox.Size = new System.Drawing.Size(126, 16);
|
||||
this.TLSAllowInsecureCheckBox.TabIndex = 0;
|
||||
this.TLSAllowInsecureCheckBox.Text = "TLS AllowInsecure";
|
||||
this.TLSAllowInsecureCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// XrayConeCheckBox
|
||||
//
|
||||
this.XrayConeCheckBox.AutoSize = true;
|
||||
this.XrayConeCheckBox.Location = new System.Drawing.Point(6, 15);
|
||||
this.XrayConeCheckBox.Name = "XrayConeCheckBox";
|
||||
this.XrayConeCheckBox.Size = new System.Drawing.Size(336, 16);
|
||||
this.XrayConeCheckBox.TabIndex = 1;
|
||||
this.XrayConeCheckBox.TabIndex = 0;
|
||||
this.XrayConeCheckBox.Text = "FullCone Support (Required Server Xray-core v1.3.0+)";
|
||||
this.XrayConeCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// TLSAllowInsecureCheckBox
|
||||
//
|
||||
this.TLSAllowInsecureCheckBox.AutoSize = true;
|
||||
this.TLSAllowInsecureCheckBox.Location = new System.Drawing.Point(6, 42);
|
||||
this.TLSAllowInsecureCheckBox.Name = "TLSAllowInsecureCheckBox";
|
||||
this.TLSAllowInsecureCheckBox.Size = new System.Drawing.Size(126, 16);
|
||||
this.TLSAllowInsecureCheckBox.TabIndex = 1;
|
||||
this.TLSAllowInsecureCheckBox.Text = "TLS AllowInsecure";
|
||||
this.TLSAllowInsecureCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// UseMuxCheckBox
|
||||
//
|
||||
this.UseMuxCheckBox.AutoSize = true;
|
||||
this.UseMuxCheckBox.Location = new System.Drawing.Point(148, 42);
|
||||
this.UseMuxCheckBox.Name = "UseMuxCheckBox";
|
||||
this.UseMuxCheckBox.Size = new System.Drawing.Size(66, 16);
|
||||
this.UseMuxCheckBox.TabIndex = 1;
|
||||
this.UseMuxCheckBox.TabIndex = 2;
|
||||
this.UseMuxCheckBox.Text = "Use Mux";
|
||||
this.UseMuxCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@@ -680,7 +725,7 @@ namespace Netch.Forms
|
||||
this.KCPGroupBox.Location = new System.Drawing.Point(9, 75);
|
||||
this.KCPGroupBox.Name = "KCPGroupBox";
|
||||
this.KCPGroupBox.Size = new System.Drawing.Size(427, 204);
|
||||
this.KCPGroupBox.TabIndex = 2;
|
||||
this.KCPGroupBox.TabIndex = 3;
|
||||
this.KCPGroupBox.TabStop = false;
|
||||
this.KCPGroupBox.Text = "KCP";
|
||||
//
|
||||
@@ -1012,6 +1057,8 @@ namespace Netch.Forms
|
||||
this.PortGroupBox.PerformLayout();
|
||||
this.NFTabPage.ResumeLayout(false);
|
||||
this.NFTabPage.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.TAPTabPage.ResumeLayout(false);
|
||||
this.TUNTAPGroupBox.ResumeLayout(false);
|
||||
this.TUNTAPGroupBox.PerformLayout();
|
||||
@@ -1047,7 +1094,6 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.Label Socks5PortLabel;
|
||||
private System.Windows.Forms.TextBox Socks5PortTextBox;
|
||||
private System.Windows.Forms.CheckBox ResolveServerHostnameCheckBox;
|
||||
private System.Windows.Forms.CheckBox BootShadowsocksFromDLLCheckBox;
|
||||
private System.Windows.Forms.GroupBox TUNTAPGroupBox;
|
||||
private System.Windows.Forms.CheckBox UseFakeDNSCheckBox;
|
||||
private System.Windows.Forms.CheckBox ProxyDNSCheckBox;
|
||||
@@ -1061,7 +1107,7 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.Label TUNTAPAddressLabel;
|
||||
private System.Windows.Forms.TextBox TUNTAPAddressTextBox;
|
||||
private System.Windows.Forms.Button GlobalBypassIPsButton;
|
||||
private System.Windows.Forms.CheckBox ModifySystemDNSCheckBox;
|
||||
private System.Windows.Forms.CheckBox DNSRedirectorCheckBox;
|
||||
private System.Windows.Forms.Button ControlButton;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.TabPage OtherTabPage;
|
||||
@@ -1107,13 +1153,18 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.Label ChinaDNSLabel;
|
||||
private System.Windows.Forms.TextBox OtherDNSTextBox;
|
||||
private System.Windows.Forms.TextBox ChinaDNSTextBox;
|
||||
private System.Windows.Forms.TextBox ModifiedDNSTextBox;
|
||||
private System.Windows.Forms.Label ModifiedDNSLabel;
|
||||
private System.Windows.Forms.TextBox RDRDNSTextBox;
|
||||
private System.Windows.Forms.Label RDRDNSLabel;
|
||||
private System.Windows.Forms.CheckBox RedirectorSSCheckBox;
|
||||
private System.Windows.Forms.Label ServerPingTypeLabel;
|
||||
private System.Windows.Forms.RadioButton TCPingRadioBtn;
|
||||
private System.Windows.Forms.RadioButton ICMPingRadioBtn;
|
||||
private System.Windows.Forms.ComboBox ProcessProxyProtocolComboBox;
|
||||
private System.Windows.Forms.Label ProcessProxyProtocolLabel;
|
||||
private System.Windows.Forms.CheckBox ICMPRedirectorCheckBox;
|
||||
private System.Windows.Forms.TextBox ModifiedICMPTextBox;
|
||||
private System.Windows.Forms.Label RDRICMPLabel;
|
||||
private System.Windows.Forms.CheckBox ChildProcessHandleCheckBox;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,6 @@ namespace Netch.Forms
|
||||
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
|
||||
Global.Settings.LocalAddress switch {"127.0.0.1" => false, "0.0.0.0" => true, _ => false});
|
||||
|
||||
BindCheckBox(BootShadowsocksFromDLLCheckBox, c => Global.Settings.BootShadowsocksFromDLL = c, Global.Settings.BootShadowsocksFromDLL);
|
||||
BindCheckBox(ResolveServerHostnameCheckBox, c => Global.Settings.ResolveServerHostname = c, Global.Settings.ResolveServerHostname);
|
||||
|
||||
BindRadioBox(ICMPingRadioBtn, _ => { }, !Global.Settings.ServerTCPing);
|
||||
@@ -109,12 +108,18 @@ namespace Netch.Forms
|
||||
|
||||
#region Process Mode
|
||||
|
||||
BindCheckBox(ModifySystemDNSCheckBox, b => Global.Settings.ModifySystemDNS = b, Global.Settings.ModifySystemDNS);
|
||||
BindCheckBox(DNSRedirectorCheckBox, b => Global.Settings.RedirectDNS = b, Global.Settings.RedirectDNS);
|
||||
|
||||
BindTextBox(ModifiedDNSTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.ModifiedDNS = s, Global.Settings.ModifiedDNS);
|
||||
BindTextBox(RDRDNSTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.RedirectDNSAddr = s, Global.Settings.RedirectDNSAddr);
|
||||
|
||||
BindCheckBox(ICMPRedirectorCheckBox, b => Global.Settings.RedirectICMP = b, Global.Settings.RedirectICMP);
|
||||
|
||||
BindTextBox(ModifiedICMPTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.RedirectICMPAddr = s, Global.Settings.RedirectICMPAddr);
|
||||
|
||||
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.RedirectorSS = s, Global.Settings.RedirectorSS);
|
||||
|
||||
BindCheckBox(ChildProcessHandleCheckBox, s => Global.Settings.ChildProcessHandle = s, Global.Settings.ChildProcessHandle);
|
||||
|
||||
BindListComboBox(ProcessProxyProtocolComboBox,
|
||||
s => Global.Settings.ProcessProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)).Cast<object>().ToArray(),
|
||||
|
||||
120
Netch/Forms/SettingForm.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -4,7 +4,6 @@ using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using WindowsJobAPI;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
@@ -30,13 +29,9 @@ namespace Netch
|
||||
/// </summary>
|
||||
private static readonly Lazy<MainForm> LazyMainForm = new(() => new MainForm());
|
||||
|
||||
public static readonly Mutex Mutex = new(false, "Global\\Netch");
|
||||
private static readonly Lazy<Mutex> LazyMutex = new(() => new Mutex(false, "Global\\Netch"));
|
||||
|
||||
#if DEBUG
|
||||
public static bool Testing = false;
|
||||
#else
|
||||
public const bool Testing = false;
|
||||
#endif
|
||||
public static Mutex Mutex => LazyMutex.Value;
|
||||
|
||||
/// <summary>
|
||||
/// 用于读取和写入的配置
|
||||
@@ -48,11 +43,6 @@ namespace Netch
|
||||
/// </summary>
|
||||
public static readonly List<Mode> Modes = new();
|
||||
|
||||
/// <summary>
|
||||
/// Windows Job API
|
||||
/// </summary>
|
||||
public static readonly JobObject Job = new();
|
||||
|
||||
public static class Flags
|
||||
{
|
||||
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
@@ -3,18 +3,48 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class Mode
|
||||
{
|
||||
public readonly string? FullName;
|
||||
private readonly Lazy<List<string>> _lazyRule;
|
||||
|
||||
public string? FullName { get; private set; }
|
||||
|
||||
public Mode(string? fullName = default)
|
||||
{
|
||||
_lazyRule = new Lazy<List<string>>(ReadRules);
|
||||
if (fullName == null)
|
||||
return;
|
||||
|
||||
FullName = fullName;
|
||||
if (!File.Exists(FullName))
|
||||
return;
|
||||
|
||||
var text = File.ReadLines(FullName).First();
|
||||
|
||||
// load head
|
||||
if (text.First() != '#')
|
||||
throw new Exception($"mode {FullName} head not found at Line 0");
|
||||
|
||||
var split = text.Substring(1).SplitTrimEntries(',');
|
||||
Remark = split[0];
|
||||
|
||||
var typeResult = int.TryParse(split.ElementAtOrDefault(1), out var type);
|
||||
Type = typeResult ? type : 0;
|
||||
// TODO throw NotSupportedModeTypeException
|
||||
|
||||
var bypassChinaResult = int.TryParse(split.ElementAtOrDefault(2), out var bypassChina);
|
||||
BypassChina = this.ClientRouting() && bypassChinaResult && bypassChina == 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 规则
|
||||
/// </summary>
|
||||
public readonly List<string> Rule = new();
|
||||
public List<string> Rule => _lazyRule.Value;
|
||||
|
||||
/// <summary>
|
||||
/// 绕过中国(0. 不绕过 1. 绕过)
|
||||
@@ -44,15 +74,6 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public int Type { get; set; } = 0;
|
||||
|
||||
public Mode(string fullName)
|
||||
{
|
||||
FullName = fullName;
|
||||
}
|
||||
|
||||
public Mode()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件相对路径(必须是存在的文件)
|
||||
/// </summary>
|
||||
@@ -78,30 +99,21 @@ namespace Netch.Models
|
||||
relativePath.Replace(">", "");
|
||||
relativePath.Replace(".h", ".txt");
|
||||
|
||||
var mode = Global.Modes.FirstOrDefault(m => m!.FullName != null && m.RelativePath!.Equals(relativePath.ToString()));
|
||||
var mode = Global.Modes.FirstOrDefault(m => m.FullName != null && m.RelativePath!.Equals(relativePath.ToString()));
|
||||
|
||||
if (mode == null)
|
||||
{
|
||||
Logging.Warning($"{relativePath} file included in {Remark} not found");
|
||||
}
|
||||
else if (mode == this)
|
||||
{
|
||||
Logging.Warning("Can't self-reference");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode.Type != Type)
|
||||
{
|
||||
Logging.Warning($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode.Rule.Any(rule => rule.StartsWith("#include")))
|
||||
Logging.Warning("Cannot reference mode that reference other mode");
|
||||
else
|
||||
result.AddRange(mode.FullRule);
|
||||
}
|
||||
}
|
||||
throw new MessageException($"{relativePath} file included in {Remark} not found");
|
||||
|
||||
if (mode == this)
|
||||
throw new MessageException("Can't self-reference");
|
||||
|
||||
if (mode.Type != Type)
|
||||
throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
|
||||
|
||||
if (mode.Rule.Any(rule => rule.StartsWith("#include")))
|
||||
throw new Exception("Cannot reference mode that reference other mode");
|
||||
|
||||
result.AddRange(mode.FullRule);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -113,6 +125,14 @@ namespace Netch.Models
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> ReadRules()
|
||||
{
|
||||
if (FullName == null || !File.Exists(FullName))
|
||||
return new List<string>();
|
||||
|
||||
return File.ReadLines(FullName!).Skip(1).ToList();
|
||||
}
|
||||
|
||||
public void WriteFile(string? fullName = null)
|
||||
{
|
||||
if (fullName != null)
|
||||
|
||||
121
Netch/Models/ParameterBase.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public abstract class ParameterBase
|
||||
{
|
||||
// null value par
|
||||
|
||||
private readonly bool _full;
|
||||
|
||||
protected readonly string ParametersSeparate = " ";
|
||||
protected readonly string Separate = " ";
|
||||
protected readonly string VerbPrefix = "-";
|
||||
protected readonly string FullPrefix = "--";
|
||||
|
||||
protected ParameterBase()
|
||||
{
|
||||
_full = !GetType().IsDefined(typeof(VerbAttribute));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var parameters = GetType().GetProperties().Select(PropToParameter).Where(s => s != null).Cast<string>();
|
||||
return string.Join(ParametersSeparate, parameters).Trim();
|
||||
}
|
||||
|
||||
private string? PropToParameter(PropertyInfo p)
|
||||
{
|
||||
// prefix
|
||||
bool full;
|
||||
if (p.IsDefined(typeof(VerbAttribute)))
|
||||
full = false;
|
||||
else if (p.IsDefined(typeof(FullAttribute)))
|
||||
full = true;
|
||||
else
|
||||
full = _full;
|
||||
|
||||
var prefix = full ? FullPrefix : VerbPrefix;
|
||||
// key
|
||||
var key = p.GetCustomAttribute<RealNameAttribute>()?.Name ?? p.Name;
|
||||
|
||||
// build
|
||||
var value = p.GetValue(this);
|
||||
switch (value)
|
||||
{
|
||||
case bool b:
|
||||
return b ? $"{prefix}{key}" : null;
|
||||
default:
|
||||
if ((value?.ToString() ?? null).IsNullOrWhiteSpace())
|
||||
return p.IsDefined(typeof(OptionalAttribute)) ? null : throw new RequiredArgumentValueInvalidException(p.Name, this, null);
|
||||
|
||||
if (p.IsDefined(typeof(QuoteAttribute)))
|
||||
value = $"\"{value}\"";
|
||||
|
||||
return $"{prefix}{key}{Separate}{value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
|
||||
public class VerbAttribute : Attribute
|
||||
{
|
||||
// Don't use verb and full both on one class or property
|
||||
// if you did, will take verb
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
|
||||
public class FullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class OptionalAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class QuoteAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class RealNameAttribute : Attribute
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public RealNameAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RequiredArgumentValueInvalidException : Exception
|
||||
{
|
||||
public string? ArgumentName { get; }
|
||||
|
||||
public object? ArgumentObject { get; }
|
||||
|
||||
private readonly string? _message;
|
||||
|
||||
private const string DefaultMessage = "{0}'s Argument \"{1}\" value invalid. A required argument's value can't be null or empty.";
|
||||
|
||||
public override string Message => _message ?? string.Format(DefaultMessage, ArgumentObject!.GetType(), ArgumentName);
|
||||
|
||||
public RequiredArgumentValueInvalidException()
|
||||
{
|
||||
_message = "Some Argument value invalid. A required argument value's can't be null or empty.";
|
||||
}
|
||||
|
||||
public RequiredArgumentValueInvalidException(string argumentName, object argumentObject, string? message)
|
||||
{
|
||||
ArgumentName = argumentName;
|
||||
ArgumentObject = argumentObject;
|
||||
_message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,11 +102,6 @@ namespace Netch.Models
|
||||
|
||||
public AioDNSConfig AioDNS { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用DLL启动Shadowsocks
|
||||
/// </summary>
|
||||
public bool BootShadowsocksFromDLL { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 全局绕过 IP 列表
|
||||
/// </summary>
|
||||
@@ -158,14 +153,24 @@ namespace Netch.Models
|
||||
public int ModeComboBoxSelectedIndex { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 要修改为的系统 DNS
|
||||
/// 转发DNS地址
|
||||
/// </summary>
|
||||
public string ModifiedDNS { get; set; } = "1.1.1.1,8.8.8.8";
|
||||
public string RedirectDNSAddr { get; set; } = "8.8.8.8";
|
||||
|
||||
/// <summary>
|
||||
/// 修改系统 DNS
|
||||
/// 是否开启DNS转发
|
||||
/// </summary>
|
||||
public bool ModifySystemDNS { get; set; } = false;
|
||||
public bool RedirectDNS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 转发ICMP地址
|
||||
/// </summary>
|
||||
public string RedirectICMPAddr { get; set; } = "1.2.4.8";
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启ICMP转发
|
||||
/// </summary>
|
||||
public bool RedirectICMP { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// GFWList
|
||||
@@ -202,6 +207,11 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public bool RedirectorSS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否代理子进程
|
||||
/// </summary>
|
||||
public bool ChildProcessHandle { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Redirector TCP 占用端口
|
||||
/// </summary>
|
||||
@@ -272,11 +282,6 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public TUNTAPConfig TUNTAP { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// UDP Socket 占用端口
|
||||
/// </summary>
|
||||
public ushort UDPSocketPort { get; set; } = 18291;
|
||||
|
||||
/// <summary>
|
||||
/// 是否打开软件时更新订阅
|
||||
/// </summary>
|
||||
|
||||
@@ -1,26 +1,56 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using Vanara.PInvoke;
|
||||
using static Vanara.PInvoke.User32;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public static class Netch
|
||||
{
|
||||
private static readonly Stopwatch Stopwatch = new();
|
||||
|
||||
public static void StartStopwatch(string name)
|
||||
{
|
||||
if (Stopwatch.IsRunning)
|
||||
throw new Exception();
|
||||
|
||||
Stopwatch.Start();
|
||||
Console.WriteLine($"Start {name} Stopwatch");
|
||||
}
|
||||
|
||||
public static void TimePoint(string name, bool restart = true)
|
||||
{
|
||||
if (!Stopwatch.IsRunning)
|
||||
throw new Exception();
|
||||
|
||||
Stopwatch.Stop();
|
||||
Console.WriteLine($"{name} Stopwatch: {Stopwatch.ElapsedMilliseconds}");
|
||||
if (restart)
|
||||
Stopwatch.Restart();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
#if DEBUG
|
||||
AttachConsole();
|
||||
#else
|
||||
if (args.Contains("-console"))
|
||||
if (!NativeMethods.AttachConsole(-1))
|
||||
NativeMethods.AllocConsole();
|
||||
AttachConsole();
|
||||
#endif
|
||||
StartStopwatch("Netch");
|
||||
|
||||
// 设置当前目录
|
||||
Directory.SetCurrentDirectory(Global.NetchDir);
|
||||
@@ -36,14 +66,15 @@ namespace Netch
|
||||
if (!Directory.Exists(item))
|
||||
Directory.CreateDirectory(item);
|
||||
|
||||
TimePoint("Clean Old, Create Directory");
|
||||
// 加载配置
|
||||
Configuration.Load();
|
||||
|
||||
TimePoint("Load Configuration");
|
||||
// 检查是否已经运行
|
||||
if (!Global.Mutex.WaitOne(0, false))
|
||||
{
|
||||
OnlyInstance.Send(OnlyInstance.Commands.Show);
|
||||
Logging.Info("唤起单实例");
|
||||
ShowOpened();
|
||||
|
||||
// 退出进程
|
||||
Environment.Exit(1);
|
||||
@@ -72,11 +103,8 @@ namespace Netch
|
||||
|
||||
Logging.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Task.Run(() => { Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); });
|
||||
Task.Run(() =>
|
||||
{
|
||||
Logging.Info("启动单实例");
|
||||
OnlyInstance.Server();
|
||||
});
|
||||
|
||||
TimePoint("Get Info, Pre-Form");
|
||||
|
||||
// 绑定错误捕获
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
@@ -87,10 +115,52 @@ namespace Netch
|
||||
Application.Run(Global.MainForm);
|
||||
}
|
||||
|
||||
private static void AttachConsole()
|
||||
{
|
||||
if (!NativeMethods.AttachConsole(-1))
|
||||
NativeMethods.AllocConsole();
|
||||
}
|
||||
|
||||
public static void Application_OnException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
Logging.Error(e.Exception.ToString());
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
}
|
||||
|
||||
private static void ShowOpened()
|
||||
{
|
||||
HWND GetWindowHandleByPidAndTitle(int process, string title)
|
||||
{
|
||||
var sb = new StringBuilder(256);
|
||||
HWND pLast = IntPtr.Zero;
|
||||
do
|
||||
{
|
||||
pLast = FindWindowEx(HWND.NULL, pLast, null, null);
|
||||
GetWindowThreadProcessId(pLast, out var id);
|
||||
if (id != process)
|
||||
continue;
|
||||
|
||||
if (GetWindowText(pLast, sb, sb.Capacity) <= 0)
|
||||
continue;
|
||||
|
||||
if (sb.ToString().Equals(title))
|
||||
return pLast;
|
||||
} while (pLast != IntPtr.Zero);
|
||||
|
||||
return HWND.NULL;
|
||||
}
|
||||
|
||||
var self = Process.GetCurrentProcess();
|
||||
var activeProcess = Process.GetProcessesByName("Netch").Single(p => p.Id != self.Id);
|
||||
HWND handle = activeProcess.MainWindowHandle;
|
||||
if (handle.IsNull)
|
||||
handle = GetWindowHandleByPidAndTitle(activeProcess.Id, "Netch");
|
||||
|
||||
if (handle.IsNull)
|
||||
return;
|
||||
|
||||
ShowWindow(handle, ShowWindowCommand.SW_NORMAL);
|
||||
SwitchToThisWindow(handle, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,9 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- <EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -43,6 +46,10 @@
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.2.4089">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.1" />
|
||||
@@ -51,8 +58,7 @@
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.5" />
|
||||
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
|
||||
<PackageReference Include="WindowsJobAPI" Version="5.0.1" />
|
||||
<PackageReference Include="WindowsProxy" Version="5.0.0" />
|
||||
<PackageReference Include="WindowsProxy" Version="5.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
|
||||
64
Netch/Properties/Resources.Designer.cs
generated
@@ -1,10 +1,10 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace Netch.Properties {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
@@ -33,7 +33,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
@@ -47,8 +47,8 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
@@ -61,7 +61,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] _7za {
|
||||
get {
|
||||
@@ -71,17 +71,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] abp_js {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("abp_js", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap CopyLink {
|
||||
get {
|
||||
@@ -91,17 +81,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] defaultTUNTAP {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("defaultTUNTAP", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap delete {
|
||||
get {
|
||||
@@ -111,7 +91,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap edit {
|
||||
get {
|
||||
@@ -121,7 +101,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// 查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon icon {
|
||||
get {
|
||||
@@ -131,7 +111,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap Netch {
|
||||
get {
|
||||
@@ -141,7 +121,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap speed {
|
||||
get {
|
||||
@@ -151,7 +131,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap Sponsor {
|
||||
get {
|
||||
@@ -161,7 +141,7 @@ namespace Netch.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] zh_CN {
|
||||
get {
|
||||
|
||||
@@ -118,10 +118,6 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089</value>
|
||||
@@ -150,10 +146,6 @@
|
||||
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\abp.js.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="7za" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\7za.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089</value>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[Generic]
|
||||
Address = 10.0.236.10
|
||||
Netmask = 255.255.255.0
|
||||
Gateway = 10.0.236.1
|
||||
DNS = 1.1.1.1
|
||||
UseCustomDNS = False
|
||||
@@ -165,6 +165,9 @@
|
||||
"SS DLL": "SS DLL",
|
||||
"Modify System DNS": "修改系统 DNS",
|
||||
"Proxy Protocol": "代理协议",
|
||||
"DNS Redirector": "DNS转发",
|
||||
"ICMP Redirector": "ICMP转发",
|
||||
"Child Process Handle": "子进程代理",
|
||||
"ProfileCount": "快捷配置数量",
|
||||
"Delay test after start": "启动后延迟测试",
|
||||
"ServerPingType": "测速方式",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks.Form
|
||||
{
|
||||
@@ -8,7 +9,7 @@ namespace Netch.Servers.Shadowsocks.Form
|
||||
{
|
||||
server ??= new Shadowsocks();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
|
||||
CreateTextBox("Password", "Password", s => !s.IsNullOrWhiteSpace(), s => server.Password = s, server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", SSGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
CreateTextBox("Plugin", "Plugin", s => true, s => server.Plugin = s, server.Plugin);
|
||||
CreateTextBox("PluginsOption", "Plugin Options", s => true, s => server.PluginOption = s, server.PluginOption);
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
public class SSController : Guard, IServerController
|
||||
{
|
||||
public bool DllFlag;
|
||||
|
||||
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; } = new[] {"listening at"};
|
||||
@@ -28,70 +24,60 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
|
||||
DllFlag = Global.Settings.BootShadowsocksFromDLL && mode.Type is 0 or 1 or 2 && !server.HasPlugin();
|
||||
|
||||
//从DLL启动Shaowsocks
|
||||
if (DllFlag)
|
||||
var command = new SSParameter
|
||||
{
|
||||
State = State.Starting;
|
||||
var client = Encoding.UTF8.GetBytes($"{this.LocalAddress()}:{this.Socks5LocalPort()}");
|
||||
var remote = Encoding.UTF8.GetBytes($"{server.AutoResolveHostname()}:{server.Port}");
|
||||
var passwd = Encoding.UTF8.GetBytes($"{server.Password}");
|
||||
var method = Encoding.UTF8.GetBytes($"{server.EncryptMethod}");
|
||||
if (!ShadowsocksDLL.Info(client, remote, passwd, method))
|
||||
{
|
||||
State = State.Stopped;
|
||||
throw new MessageException("DLL SS INFO 设置失败!");
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS INFO 设置成功!");
|
||||
|
||||
if (!ShadowsocksDLL.Start())
|
||||
{
|
||||
State = State.Stopped;
|
||||
throw new MessageException("DLL SS 启动失败!");
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS 启动成功!");
|
||||
State = State.Started;
|
||||
return;
|
||||
}
|
||||
|
||||
#region Argument
|
||||
|
||||
var argument = new StringBuilder();
|
||||
argument.Append($"-s {server.AutoResolveHostname()} " + $"-p {server.Port} " + $"-b {this.LocalAddress()} " +
|
||||
$"-l {this.Socks5LocalPort()} " + $"-m {server.EncryptMethod} " + $"-k \"{server.Password}\" " + "-u");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(server.Plugin) && !string.IsNullOrWhiteSpace(server.PluginOption))
|
||||
argument.Append($" --plugin {server.Plugin}" + $" --plugin-opts \"{server.PluginOption}\"");
|
||||
s = server.AutoResolveHostname(),
|
||||
p = server.Port,
|
||||
b = this.LocalAddress(),
|
||||
l = this.Socks5LocalPort(),
|
||||
m = server.EncryptMethod,
|
||||
k = server.Password,
|
||||
u = true,
|
||||
plugin = server.Plugin,
|
||||
plugin_opts = server.PluginOption
|
||||
};
|
||||
|
||||
if (mode.BypassChina)
|
||||
argument.Append($" --acl \"{Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}\"");
|
||||
command.acl = $"{Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}";
|
||||
|
||||
#endregion
|
||||
StartInstanceAuto(command.ToString());
|
||||
}
|
||||
|
||||
StartInstanceAuto(argument.ToString());
|
||||
[Verb]
|
||||
private class SSParameter : ParameterBase
|
||||
{
|
||||
public string? s { get; set; }
|
||||
|
||||
public ushort? p { get; set; }
|
||||
|
||||
public string? b { get; set; }
|
||||
|
||||
public ushort? l { get; set; }
|
||||
|
||||
public string? m { get; set; }
|
||||
|
||||
public string? k { get; set; }
|
||||
|
||||
public bool u { get; set; }
|
||||
|
||||
[Full]
|
||||
[Optional]
|
||||
public string? plugin { get; set; }
|
||||
|
||||
[Full]
|
||||
[Optional]
|
||||
[RealName("plugin-opts")]
|
||||
public string? plugin_opts { get; set; }
|
||||
|
||||
[Full]
|
||||
[Quote]
|
||||
[Optional]
|
||||
public string? acl { get; set; }
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
if (DllFlag)
|
||||
ShadowsocksDLL.Stop();
|
||||
else
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
private class ShadowsocksDLL
|
||||
{
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Info(byte[] client, byte[] remote, byte[] passwd, byte[] method);
|
||||
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Start();
|
||||
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Stop();
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public IEnumerable<Server> ParseSsdUri(string s)
|
||||
{
|
||||
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)));
|
||||
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
|
||||
|
||||
return json.servers.Select(server => new Shadowsocks
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string? Password { get; set; }
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR.Form
|
||||
{
|
||||
@@ -8,7 +9,7 @@ namespace Netch.Servers.ShadowsocksR.Form
|
||||
{
|
||||
server ??= new ShadowsocksR();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
|
||||
CreateTextBox("Password", "Password", s => !s.IsNullOrWhiteSpace(), s => server.Password = s, server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", SSRGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
CreateComboBox("Protocol", "Protocol", SSRGlobal.Protocols, s => server.Protocol = s, server.Protocol);
|
||||
CreateTextBox("ProtocolParam", "Protocol Param", s => true, s => server.ProtocolParam = s, server.ProtocolParam);
|
||||
|
||||
@@ -24,31 +24,64 @@ namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
|
||||
#region Argument
|
||||
|
||||
var argument = new StringBuilder();
|
||||
argument.Append($"-s {server.AutoResolveHostname()} -p {server.Port} -k \"{server.Password}\" -m {server.EncryptMethod} -t 120");
|
||||
if (!string.IsNullOrEmpty(server.Protocol))
|
||||
var command = new SSRParameter
|
||||
{
|
||||
argument.Append($" -O {server.Protocol}");
|
||||
if (!string.IsNullOrEmpty(server.ProtocolParam))
|
||||
argument.Append($" -G \"{server.ProtocolParam}\"");
|
||||
}
|
||||
s = server.AutoResolveHostname(),
|
||||
p = server.Port,
|
||||
k = server.Password,
|
||||
m = server.EncryptMethod,
|
||||
t = "120",
|
||||
O = server.Protocol,
|
||||
G = server.ProtocolParam,
|
||||
o = server.OBFS,
|
||||
g = server.OBFSParam,
|
||||
b = this.LocalAddress(),
|
||||
l = this.Socks5LocalPort(),
|
||||
u = true
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(server.OBFS))
|
||||
{
|
||||
argument.Append($" -o {server.OBFS}");
|
||||
if (!string.IsNullOrEmpty(server.OBFSParam))
|
||||
argument.Append($" -g \"{server.OBFSParam}\"");
|
||||
}
|
||||
|
||||
argument.Append($" -b {this.LocalAddress()} -l {this.Socks5LocalPort()} -u");
|
||||
if (mode.BypassChina)
|
||||
argument.Append($" --acl \"{Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}\"");
|
||||
command.acl = $"{Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}";
|
||||
|
||||
#endregion
|
||||
StartInstanceAuto(command.ToString());
|
||||
}
|
||||
|
||||
StartInstanceAuto(argument.ToString());
|
||||
[Verb]
|
||||
class SSRParameter : ParameterBase
|
||||
{
|
||||
public string? s { get; set; }
|
||||
|
||||
public ushort? p { get; set; }
|
||||
|
||||
[Quote]
|
||||
public string? k { get; set; }
|
||||
|
||||
public string? m { get; set; }
|
||||
|
||||
public string? t { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? O { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? G { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? o { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? g { get; set; }
|
||||
|
||||
public string? b { get; set; }
|
||||
|
||||
public ushort? l { get; set; }
|
||||
|
||||
public bool u { get; set; }
|
||||
|
||||
[Full]
|
||||
[Quote]
|
||||
[Optional]
|
||||
public string? acl { get; set; }
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
|
||||
@@ -7,26 +7,16 @@ namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
public override string Type { get; } = "SSR";
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod { get; set; } = SSRGlobal.EncryptMethods[0];
|
||||
|
||||
/// <summary>
|
||||
/// 混淆
|
||||
/// </summary>
|
||||
public string OBFS { get; set; } = SSRGlobal.OBFSs[0];
|
||||
|
||||
/// <summary>
|
||||
/// 混淆参数
|
||||
/// </summary>
|
||||
public string? OBFSParam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod { get; set; } = SSRGlobal.EncryptMethods[0];
|
||||
|
||||
/// <summary>
|
||||
/// 协议
|
||||
/// </summary>
|
||||
@@ -36,6 +26,16 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// 协议参数
|
||||
/// </summary>
|
||||
public string? ProtocolParam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 混淆
|
||||
/// </summary>
|
||||
public string OBFS { get; set; } = SSRGlobal.OBFSs[0];
|
||||
|
||||
/// <summary>
|
||||
/// 混淆参数
|
||||
/// </summary>
|
||||
public string? OBFSParam { get; set; }
|
||||
}
|
||||
|
||||
public class SSRGlobal
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/// <summary>
|
||||
/// 额外 ID
|
||||
/// </summary>
|
||||
public string aid { get; set; } = string.Empty;
|
||||
public int aid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名(HTTP,WS)
|
||||
@@ -38,7 +38,7 @@
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public string port { get; set; } = string.Empty;
|
||||
public ushort port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
@@ -58,6 +58,6 @@
|
||||
/// <summary>
|
||||
/// 链接版本
|
||||
/// </summary>
|
||||
public string v { get; set; } = string.Empty;
|
||||
public int v { get; set; } = 2;
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,7 @@ namespace Netch.Servers.V2ray
|
||||
var parameter = new Dictionary<string, string>();
|
||||
// protocol-specific fields
|
||||
parameter.Add("type", server.TransferProtocol);
|
||||
if (server.EncryptMethod == "none")
|
||||
// VLESS outbounds[].settings.encryption,当前可选值只有 none
|
||||
parameter.Add("encryption", server.EncryptMethod);
|
||||
parameter.Add("encryption", server.EncryptMethod);
|
||||
|
||||
// transport-specific fields
|
||||
switch (server.TransferProtocol)
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
@@ -43,12 +44,12 @@ namespace Netch.Servers.VMess
|
||||
|
||||
var vmessJson = JsonSerializer.Serialize(new V2rayNSharing
|
||||
{
|
||||
v = "2",
|
||||
v = 2,
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port.ToString(),
|
||||
port = server.Port,
|
||||
id = server.UserID,
|
||||
aid = server.AlterID.ToString(),
|
||||
aid = server.AlterID,
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
@@ -85,19 +86,20 @@ namespace Netch.Servers.VMess
|
||||
return V2rayUtils.ParseVUri(text);
|
||||
}
|
||||
|
||||
V2rayNSharing vmess = JsonSerializer.Deserialize<V2rayNSharing>(s)!;
|
||||
V2rayNSharing vmess = JsonSerializer.Deserialize<V2rayNSharing>(s,
|
||||
new JsonSerializerOptions {NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString})!;
|
||||
|
||||
data.Remark = vmess.ps;
|
||||
data.Hostname = vmess.add;
|
||||
data.Port = ushort.Parse(vmess.port);
|
||||
data.Port = vmess.port;
|
||||
data.UserID = vmess.id;
|
||||
data.AlterID = int.Parse(vmess.aid);
|
||||
data.AlterID = vmess.aid;
|
||||
data.TransferProtocol = vmess.net;
|
||||
data.FakeType = vmess.type;
|
||||
|
||||
if (data.TransferProtocol == "quic")
|
||||
{
|
||||
if (VMessGlobal.QUIC.Contains(vmess.host))
|
||||
if (VMessGlobal.QUIC.Contains(vmess.host!))
|
||||
{
|
||||
data.QUICSecure = vmess.host;
|
||||
data.QUICSecret = vmess.path;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Controllers;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
@@ -14,65 +14,140 @@ namespace Netch.Updater
|
||||
{
|
||||
public class Updater
|
||||
{
|
||||
private static IEnumerable<string> _keepDirectory = new List<string>(new[] {"data", "mode\\Custom"});
|
||||
private readonly string _targetPath;
|
||||
private readonly string _tempFolder;
|
||||
private readonly string _updateFilePath;
|
||||
#region Download Update and apply update
|
||||
|
||||
private Updater(string updateFilePath, string targetPath)
|
||||
/// <summary>
|
||||
/// Download Update and apply update (all arguments are FullPath)
|
||||
/// </summary>
|
||||
/// <param name="downloadDirectory"></param>
|
||||
/// <param name="installDirectory"></param>
|
||||
/// <param name="onDownloadProgressChanged"></param>
|
||||
/// <param name="keyword"></param>
|
||||
/// <exception cref="MessageException"></exception>
|
||||
public static void DownloadAndUpdate(string downloadDirectory,
|
||||
string installDirectory,
|
||||
DownloadProgressChangedEventHandler onDownloadProgressChanged,
|
||||
string? keyword = null)
|
||||
{
|
||||
_targetPath = targetPath;
|
||||
_tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(_tempFolder);
|
||||
UpdateChecker.GetLatestUpdateFileNameAndHash(out var updateFileName, out var sha256, keyword);
|
||||
|
||||
_updateFilePath = Path.GetFullPath(updateFilePath);
|
||||
_keepDirectory = _keepDirectory.Select(s => Path.Combine(targetPath, s));
|
||||
// update file Full Path
|
||||
var updateFile = Path.Combine(downloadDirectory, updateFileName);
|
||||
var updater = new Updater(updateFile, installDirectory);
|
||||
|
||||
if (File.Exists(updateFile))
|
||||
{
|
||||
if (Utils.Utils.SHA256CheckSum(updateFile) == sha256)
|
||||
{
|
||||
updater.ApplyUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
File.Delete(updateFile);
|
||||
}
|
||||
|
||||
DownloadUpdateFile(onDownloadProgressChanged, updateFile, sha256);
|
||||
updater.ApplyUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download Update File
|
||||
/// </summary>
|
||||
/// <param name="onDownloadProgressChanged"></param>
|
||||
/// <param name="fileFullPath"></param>
|
||||
/// <param name="sha256"></param>
|
||||
/// <exception cref="MessageException"></exception>
|
||||
private static void DownloadUpdateFile(DownloadProgressChangedEventHandler onDownloadProgressChanged, string fileFullPath, string sha256)
|
||||
{
|
||||
using WebClient client = new();
|
||||
try
|
||||
{
|
||||
client.DownloadProgressChanged += onDownloadProgressChanged;
|
||||
client.DownloadFile(new Uri(UpdateChecker.LatestRelease.assets[0].browser_download_url), fileFullPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.DownloadProgressChanged -= onDownloadProgressChanged;
|
||||
}
|
||||
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
|
||||
throw new MessageException(i18N.Translate("The downloaded file has the wrong hash"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly string _updateFile;
|
||||
private readonly string _installDirectory;
|
||||
private readonly string _tempDirectory;
|
||||
|
||||
private Updater(string updateFile, string installDirectory)
|
||||
{
|
||||
_updateFile = updateFile;
|
||||
_installDirectory = installDirectory;
|
||||
_tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
|
||||
Directory.CreateDirectory(_tempDirectory);
|
||||
}
|
||||
|
||||
#region Apply Update
|
||||
|
||||
private static readonly ImmutableArray<string> KeepDirectories = new List<string> {"data", "mode\\Custom"}.ToImmutableArray();
|
||||
|
||||
private void ApplyUpdate()
|
||||
{
|
||||
var extractPath = Path.Combine(_tempFolder, "extract");
|
||||
// extract Update file to {tempDirectory}\extract
|
||||
var extractPath = Path.Combine(_tempDirectory, "extract");
|
||||
int exitCode;
|
||||
if ((exitCode = Extract(extractPath, true)) != 0)
|
||||
throw new Exception(i18N.Translate($"7za exit with code {exitCode}"));
|
||||
|
||||
// rename install directory files with .old suffix unless in keep folders
|
||||
MarkFilesOld();
|
||||
|
||||
MoveAllFilesOver(Path.Combine(extractPath, "Netch"), _targetPath);
|
||||
// move {tempDirectory}\extract\Netch to install folder
|
||||
MoveAllFilesOver(Path.Combine(extractPath, "Netch"), _installDirectory);
|
||||
|
||||
// save, release mutex, then exit
|
||||
Configuration.Save();
|
||||
Global.Mutex.ReleaseMutex();
|
||||
Global.MainForm.Invoke(new Action(() => { Global.Mutex.ReleaseMutex(); }));
|
||||
Process.Start(Global.NetchExecutable);
|
||||
Global.MainForm.Exit(true, false);
|
||||
}
|
||||
|
||||
private void MarkFilesOld()
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(_targetPath, "*", SearchOption.AllDirectories))
|
||||
// extend keepDirectories relative path to absolute path
|
||||
var extendedKeepDirectories = KeepDirectories.Select(d => Path.Combine(_installDirectory, d)).ToImmutableArray();
|
||||
|
||||
// weed out keep files
|
||||
List<string> filesToDelete = new();
|
||||
foreach (var file in Directory.GetFiles(_installDirectory, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (_keepDirectory.Any(p => file.StartsWith(p)))
|
||||
if (extendedKeepDirectories.Any(p => file.StartsWith(p)))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
File.Move(file, file + ".old");
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Updater wasn't able to rename file: " + file);
|
||||
}
|
||||
if (Path.GetFileName(file) is ModeHelper.DISABLE_MODE_DIRECTORY_FILENAME)
|
||||
continue;
|
||||
|
||||
filesToDelete.Add(file);
|
||||
}
|
||||
|
||||
// rename files
|
||||
foreach (var file in filesToDelete)
|
||||
File.Move(file, file + ".old");
|
||||
}
|
||||
|
||||
private int Extract(string destDirName, bool overwrite)
|
||||
{
|
||||
var temp7za = Path.Combine(_tempFolder, "7za.exe");
|
||||
// release 7za.exe to {tempDirectory}\7za.exe
|
||||
var temp7za = Path.Combine(_tempDirectory, "7za.exe");
|
||||
|
||||
if (!File.Exists(temp7za))
|
||||
File.WriteAllBytes(temp7za, Resources._7za);
|
||||
|
||||
// run 7za
|
||||
var argument = new StringBuilder();
|
||||
argument.Append($" x \"{_updateFilePath}\" -o\"{destDirName}\"");
|
||||
argument.Append($" x \"{_updateFile}\" -o\"{destDirName}\"");
|
||||
if (overwrite)
|
||||
argument.Append(" -y");
|
||||
|
||||
@@ -108,6 +183,10 @@ namespace Netch.Updater
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Clean files marked as old when start
|
||||
|
||||
public static void CleanOld(string targetPath)
|
||||
{
|
||||
foreach (var f in Directory.GetFiles(targetPath, "*.old", SearchOption.AllDirectories))
|
||||
@@ -121,40 +200,6 @@ namespace Netch.Updater
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadAndUpdate(string downloadPath,
|
||||
string targetPath,
|
||||
DownloadProgressChangedEventHandler onDownloadProgressChanged)
|
||||
{
|
||||
var keyword = (string?) null;
|
||||
|
||||
if (!UpdateChecker.GetFileNameAndHashFromMarkdownForm(UpdateChecker.LatestRelease.body, out var fileName, out var sha256, keyword))
|
||||
throw new Exception(i18N.Translate("parse release note failed"));
|
||||
|
||||
var fileFullPath = Path.Combine(downloadPath, fileName);
|
||||
var updater = new Updater(fileFullPath, targetPath);
|
||||
|
||||
if (!(File.Exists(fileFullPath) && Utils.Utils.SHA256CheckSum(fileFullPath) == sha256))
|
||||
{
|
||||
using WebClient client = new();
|
||||
try
|
||||
{
|
||||
client.DownloadProgressChanged += onDownloadProgressChanged;
|
||||
await client.DownloadFileTaskAsync(new Uri(UpdateChecker.LatestRelease.assets[0].browser_download_url), fileFullPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception(i18N.Translate("Download Update Failed", ": ") + e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.DownloadProgressChanged -= onDownloadProgressChanged;
|
||||
}
|
||||
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
|
||||
throw new Exception(i18N.Translate("The downloaded file has the wrong hash"));
|
||||
}
|
||||
|
||||
updater.ApplyUpdate();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -57,9 +57,6 @@ namespace Netch.Utils
|
||||
{
|
||||
case null:
|
||||
break;
|
||||
case SSController {DllFlag: true}:
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
break;
|
||||
case Guard instanceController:
|
||||
if (instanceController.Instance != null)
|
||||
instances.Add(instanceController.Instance);
|
||||
|
||||
@@ -33,42 +33,37 @@ namespace Netch.Utils
|
||||
{
|
||||
if (File.Exists(SETTINGS_JSON))
|
||||
{
|
||||
Global.Settings = ParseSetting(File.ReadAllText(SETTINGS_JSON));
|
||||
try
|
||||
{
|
||||
using var fileStream = File.OpenRead(SETTINGS_JSON);
|
||||
var settings = JsonSerializer.DeserializeAsync<Setting>(fileStream, JsonSerializerOptions).Result!;
|
||||
|
||||
CheckSetting(settings);
|
||||
|
||||
Global.Settings = settings;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
Utils.Open(Logging.LogFile);
|
||||
Environment.Exit(-1);
|
||||
Global.Settings = null!;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 弹出提示
|
||||
i18N.Load("System");
|
||||
|
||||
// 创建 data 文件夹并保存默认设置
|
||||
// 保存默认设置
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public static Setting ParseSetting(string text)
|
||||
private static void CheckSetting(Setting settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = JsonSerializer.Deserialize<Setting>(text, JsonSerializerOptions)!;
|
||||
settings.Profiles.RemoveAll(p => p.ServerRemark == string.Empty || p.ModeRemark == string.Empty);
|
||||
|
||||
#region Check Profile
|
||||
|
||||
foreach (var profile in settings.Profiles.Where(p => p.ServerRemark == string.Empty || p.ModeRemark == string.Empty)!)
|
||||
settings.Profiles.Remove(profile);
|
||||
|
||||
if (settings.Profiles.Any(p => settings.Profiles.Any(p1 => p1 != p && p1.Index == p.Index)))
|
||||
for (var i = 0; i < settings.Profiles.Count; i++)
|
||||
settings.Profiles[i].Index = i;
|
||||
|
||||
#endregion
|
||||
|
||||
return settings;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
return new Setting();
|
||||
}
|
||||
if (settings.Profiles.Any(p => settings.Profiles.Any(p1 => p1 != p && p1.Index == p.Index)))
|
||||
for (var i = 0; i < settings.Profiles.Count; i++)
|
||||
settings.Profiles[i].Index = i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -14,15 +14,15 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
private static HttpWebServer? _httpWebServer;
|
||||
private static string? _pacContent;
|
||||
public static readonly string PacPrefix= $"http://127.0.0.1:{Global.Settings.Pac_Port}/pac/";
|
||||
|
||||
public static string InitPACServer(string address)
|
||||
public static string InitPACServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
_pacContent = GetPacList(address);
|
||||
var prefixes = $"http://{address}:{Global.Settings.Pac_Port}/pac/";
|
||||
_pacContent = GetPacList("127.0.0.1");
|
||||
|
||||
_httpWebServer = new HttpWebServer(SendResponse, prefixes);
|
||||
_httpWebServer = new HttpWebServer(SendResponse, PacPrefix);
|
||||
Task.Run(() => _httpWebServer.StartWaitingRequest());
|
||||
|
||||
var pacUrl = GetPacUrl();
|
||||
@@ -77,7 +77,7 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
/// <returns></returns>
|
||||
public static string GetPacUrl()
|
||||
{
|
||||
return $"http://127.0.0.1:{Global.Settings.Pac_Port}/pac/?t={DateTime.Now:yyyyMMddHHmmssfff}";
|
||||
return PacPrefix + $"?t={DateTime.Now:yyyyMMddHHmmssfff}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,14 +40,23 @@ namespace Netch.Utils
|
||||
private static void Write(string text, LogLevel logLevel)
|
||||
{
|
||||
var contents = $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Global.EOF}";
|
||||
if (Global.Testing)
|
||||
#if DEBUG
|
||||
switch (logLevel)
|
||||
{
|
||||
Console.WriteLine(contents);
|
||||
return;
|
||||
case LogLevel.INFO:
|
||||
case LogLevel.WARNING:
|
||||
Console.Write(contents);
|
||||
break;
|
||||
case LogLevel.ERROR:
|
||||
Console.Error.Write(contents);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null);
|
||||
}
|
||||
|
||||
#else
|
||||
lock (FileLock)
|
||||
File.AppendAllText(LogFile, contents);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Netch.Controllers;
|
||||
@@ -12,9 +11,33 @@ namespace Netch.Utils
|
||||
public static class ModeHelper
|
||||
{
|
||||
private const string MODE_DIR = "mode";
|
||||
public const string DISABLE_MODE_DIRECTORY_FILENAME = "disabled";
|
||||
|
||||
public static readonly string ModeDirectory = Path.Combine(Global.NetchDir, $"{MODE_DIR}\\");
|
||||
|
||||
private static readonly FileSystemWatcher FileSystemWatcher;
|
||||
|
||||
static ModeHelper()
|
||||
{
|
||||
FileSystemWatcher = new FileSystemWatcher(ModeDirectory)
|
||||
{
|
||||
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName,
|
||||
IncludeSubdirectories = true,
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
|
||||
FileSystemWatcher.Changed += OnModeChanged;
|
||||
FileSystemWatcher.Created += OnModeChanged;
|
||||
FileSystemWatcher.Deleted += OnModeChanged;
|
||||
FileSystemWatcher.Renamed += OnModeChanged;
|
||||
}
|
||||
|
||||
private static void OnModeChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
Load();
|
||||
Global.MainForm.LoadModes();
|
||||
}
|
||||
|
||||
public static string GetRelativePath(string fullName)
|
||||
{
|
||||
return fullName.Substring(ModeDirectory.Length);
|
||||
@@ -25,84 +48,42 @@ namespace Netch.Utils
|
||||
return Path.Combine(ModeDirectory, relativeName);
|
||||
}
|
||||
|
||||
public static string GetFullPath(Mode mode)
|
||||
{
|
||||
return Path.Combine(ModeDirectory, mode.RelativePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从模式文件夹读取模式并为 <see cref="Forms.MainForm.ModeComboBox" /> 绑定数据
|
||||
/// 从模式文件夹读取模式
|
||||
/// </summary>
|
||||
public static void Load()
|
||||
{
|
||||
Global.Modes.Clear();
|
||||
|
||||
if (!Directory.Exists(MODE_DIR))
|
||||
return;
|
||||
|
||||
var stack = new Stack<string>();
|
||||
stack.Push(MODE_DIR);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(stack.Pop());
|
||||
try
|
||||
{
|
||||
foreach (var childDirInfo in dirInfo.GetDirectories())
|
||||
stack.Push(childDirInfo.FullName);
|
||||
|
||||
foreach (var childFileInfo in dirInfo.GetFiles().Where(info => info.Name.EndsWith(".txt")))
|
||||
LoadModeFile(childFileInfo.FullName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
LoadModeDirectory(ModeDirectory);
|
||||
|
||||
Sort();
|
||||
}
|
||||
|
||||
private static void LoadModeFile(string fullName)
|
||||
private static void LoadModeDirectory(string modeDirectory)
|
||||
{
|
||||
var mode = new Mode(fullName);
|
||||
|
||||
var content = File.ReadAllLines(fullName);
|
||||
if (content.Length == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < content.Length; i++)
|
||||
try
|
||||
{
|
||||
var text = content[i].Trim();
|
||||
foreach (var directory in Directory.GetDirectories(modeDirectory))
|
||||
LoadModeDirectory(directory);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (text.First() != '#')
|
||||
return;
|
||||
// skip Directory with a disabled file in
|
||||
if (File.Exists(Path.Combine(modeDirectory, DISABLE_MODE_DIRECTORY_FILENAME)))
|
||||
return;
|
||||
|
||||
foreach (var file in Directory.GetFiles(modeDirectory).Where(f => f.EndsWith(".txt")))
|
||||
try
|
||||
{
|
||||
var splited = text.Substring(1).SplitTrimEntries(',');
|
||||
|
||||
mode.Remark = splited[0];
|
||||
|
||||
var typeResult = int.TryParse(splited.ElementAtOrDefault(1), out var type);
|
||||
mode.Type = typeResult ? type : 0;
|
||||
|
||||
var bypassChinaResult = int.TryParse(splited.ElementAtOrDefault(2), out var bypassChina);
|
||||
mode.BypassChina = mode.ClientRouting() && bypassChinaResult && bypassChina == 1;
|
||||
Global.Modes.Add(new Mode(file));
|
||||
}
|
||||
catch
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mode.Rule.Add(text);
|
||||
}
|
||||
}
|
||||
|
||||
Global.Modes.Add(mode);
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static void Sort()
|
||||
@@ -110,21 +91,12 @@ namespace Netch.Utils
|
||||
Global.Modes.Sort((a, b) => string.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
public static void Add(Mode mode)
|
||||
{
|
||||
Global.Modes.Add(mode);
|
||||
Sort();
|
||||
Global.MainForm.LoadModes();
|
||||
}
|
||||
|
||||
public static void Delete(Mode mode)
|
||||
{
|
||||
var fullName = GetFullPath(mode);
|
||||
if (File.Exists(fullName))
|
||||
File.Delete(fullName);
|
||||
if (mode.FullName == null)
|
||||
throw new ArgumentException(nameof(mode.FullName));
|
||||
|
||||
Global.Modes.Remove(mode);
|
||||
Global.MainForm.LoadModes();
|
||||
File.Delete(mode.FullName);
|
||||
}
|
||||
|
||||
public static bool SkipServerController(Server server, Mode mode)
|
||||
@@ -141,17 +113,15 @@ namespace Netch.Utils
|
||||
};
|
||||
}
|
||||
|
||||
public static IModeController? GetModeControllerByType(int type, out ushort? port, out string portName, out PortType portType)
|
||||
public static IModeController? GetModeControllerByType(int type, out ushort? port, out string portName)
|
||||
{
|
||||
port = null;
|
||||
portName = string.Empty;
|
||||
portType = PortType.Both;
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
port = Global.Settings.RedirectorTCPPort;
|
||||
portName = "Redirector TCP";
|
||||
portType = PortType.TCP;
|
||||
return new NFController();
|
||||
case 1:
|
||||
case 2:
|
||||
@@ -160,7 +130,6 @@ namespace Netch.Utils
|
||||
case 5:
|
||||
port = Global.Settings.HTTPLocalPort;
|
||||
portName = "HTTP";
|
||||
portType = PortType.TCP;
|
||||
StatusPortInfoText.HttpPort = (ushort) port;
|
||||
return new HTTPController();
|
||||
case 4:
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class OnlyInstance
|
||||
{
|
||||
public enum Commands
|
||||
{
|
||||
Show,
|
||||
Exit
|
||||
}
|
||||
|
||||
public static event EventHandler<Commands>? Called;
|
||||
|
||||
private static void OnCalled(Commands e)
|
||||
{
|
||||
Called?.Invoke(null, e);
|
||||
}
|
||||
|
||||
public static async void Server()
|
||||
{
|
||||
try
|
||||
{
|
||||
const int tryLimit = 3;
|
||||
var i = tryLimit;
|
||||
while (i > 0)
|
||||
try
|
||||
{
|
||||
PortHelper.CheckPort(Global.Settings.UDPSocketPort, PortType.UDP);
|
||||
if (i != tryLimit)
|
||||
Configuration.Save();
|
||||
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Global.Settings.UDPSocketPort = PortHelper.GetAvailablePort(PortType.UDP);
|
||||
i--;
|
||||
}
|
||||
|
||||
var data = new byte[1024];
|
||||
var newsock = new UdpClient(new IPEndPoint(IPAddress.Loopback, Global.Settings.UDPSocketPort));
|
||||
|
||||
while (true)
|
||||
{
|
||||
var result = await newsock.ReceiveAsync();
|
||||
data = result.Buffer;
|
||||
if (Enum.TryParse<Commands>(Encoding.ASCII.GetString(data, 0, data.Length), out var command))
|
||||
OnCalled(command);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static async void Send(Commands command)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var udpClient = new UdpClient(new IPEndPoint(IPAddress.Loopback, Global.Settings.UDPSocketPort));
|
||||
udpClient.Connect(IPAddress.Loopback, Global.Settings.UDPSocketPort);
|
||||
var sendBytes = Encoding.ASCII.GetBytes(command.ToString());
|
||||
await udpClient.SendAsync(sendBytes, sendBytes.Length);
|
||||
|
||||
udpClient.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Models;
|
||||
using static Vanara.PInvoke.IpHlpApi;
|
||||
using static Vanara.PInvoke.Ws2_32;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -26,6 +28,18 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static Process? GetProcessByUsedTcpPort(ushort port)
|
||||
{
|
||||
if (port == 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
var row = GetTcpTable2().SingleOrDefault(r => ntohs((ushort) r.dwLocalPort) == port);
|
||||
if (row.dwOwningPid == 0)
|
||||
return null;
|
||||
|
||||
return Process.GetProcessById((int) row.dwOwningPid);
|
||||
}
|
||||
|
||||
private static void GetReservedPortRange(PortType portType, ref List<Range> targetList)
|
||||
{
|
||||
var process = new Process
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Netch.Utils
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Unsupported Server Type
|
||||
return JsonSerializer.Deserialize<Server>(jsonElement.GetRawText(), new JsonSerializerOptions())!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,22 @@ namespace Netch.Utils
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
var errorFlag = false;
|
||||
foreach (var line in text.GetLines())
|
||||
list.AddRange(ParseUri(line));
|
||||
{
|
||||
try
|
||||
{
|
||||
list.AddRange(ParseUri(line));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorFlag = true;
|
||||
Logging.Error(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (errorFlag)
|
||||
Utils.Open(Logging.LogFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -61,30 +75,22 @@ namespace Netch.Utils
|
||||
{
|
||||
var list = new List<Server>();
|
||||
|
||||
try
|
||||
if (text.StartsWith("tg://socks?") || text.StartsWith("https://t.me/socks?"))
|
||||
{
|
||||
if (text.StartsWith("tg://socks?") || text.StartsWith("https://t.me/socks?"))
|
||||
{
|
||||
list.AddRange(ServerHelper.GetUtilByTypeName("Socks5").ParseUri(text));
|
||||
}
|
||||
else if (text.StartsWith("Netch://"))
|
||||
{
|
||||
list.Add(ParseNetchUri(text));
|
||||
}
|
||||
else
|
||||
{
|
||||
var scheme = GetUriScheme(text);
|
||||
var util = ServerHelper.GetUtilByUriScheme(scheme);
|
||||
if (util != null)
|
||||
list.AddRange(util.ParseUri(text));
|
||||
else
|
||||
Logging.Warning($"无法处理 {scheme} 协议订阅链接");
|
||||
}
|
||||
list.AddRange(ServerHelper.GetUtilByTypeName("Socks5").ParseUri(text));
|
||||
}
|
||||
catch (Exception e)
|
||||
else if (text.StartsWith("Netch://"))
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
Utils.Open(Logging.LogFile);
|
||||
list.Add(ParseNetchUri(text));
|
||||
}
|
||||
else
|
||||
{
|
||||
var scheme = GetUriScheme(text);
|
||||
var util = ServerHelper.GetUtilByUriScheme(scheme);
|
||||
if (util != null)
|
||||
list.AddRange(util.ParseUri(text));
|
||||
else
|
||||
Logging.Warning($"无法处理 {scheme} 协议订阅链接");
|
||||
}
|
||||
|
||||
foreach (var node in list.Where(node => !node.Remark.IsNullOrWhiteSpace()))
|
||||
|
||||
@@ -48,8 +48,9 @@ namespace Netch.Utils
|
||||
var sb = new StringBuilder();
|
||||
foreach (var t in value)
|
||||
{
|
||||
if (new[] {'\\', '(', ')', '[', ']', '.'}.Any(s => s == t))
|
||||
sb.Append(@"\");
|
||||
var escapeCharacters = new[] {'\\', '*', '+', '?', '|', '{', '}', '[', ']', '(', ')', '^', '$', '.'};
|
||||
if (escapeCharacters.Any(s => s == t))
|
||||
sb.Append('\\');
|
||||
|
||||
sb.Append(t);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ namespace Netch.Utils
|
||||
{
|
||||
public static bool Open(string path)
|
||||
{
|
||||
if (Global.Testing)
|
||||
return true;
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
@@ -116,30 +114,11 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static void KillProcessByName(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var p in Process.GetProcessesByName(name))
|
||||
if (p.MainModule != null && p.MainModule.FileName.StartsWith(Global.NetchDir))
|
||||
p.Kill();
|
||||
}
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Logging.Error($"结束进程 {name} 错误:" + e.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFileVersion(string file)
|
||||
{
|
||||
return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
|
||||
}
|
||||
|
||||
|
||||
public static void DrawCenterComboBox(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Netch.Utils
|
||||
break;
|
||||
}
|
||||
|
||||
var dictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(text);
|
||||
var dictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(text)!;
|
||||
|
||||
if (!dictionary.Any())
|
||||
{
|
||||
|
||||
11
README.md
@@ -7,9 +7,9 @@
|
||||
[](https://github.com/NetchX/Netch/actions)
|
||||
[](LICENSE)
|
||||
|
||||
[中文说明](/docs/README.zh-CN.md)
|
||||
[文档网站](https://netch.org/) [常见问题](https://netch.org/#/docs/zh-CN/faq)
|
||||
|
||||
[常见问题](https://netch.org/#/docs/zh-CN/faq)
|
||||
[中文说明](README.zh-CN.md)
|
||||
|
||||
Game network accelerator
|
||||
|
||||
@@ -31,12 +31,12 @@ Currently supports the following protocols
|
||||
- ShadowsocksR
|
||||
- Trojan
|
||||
- VMess
|
||||
- VLess
|
||||
- VLESS
|
||||
|
||||
As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an NATTypeTester to test out what your NAT type is. When using SSTap to speed up some P2P gaming connections or the game is required for that kind of open NAT type, you may experience some bad situations such as unable to join the game
|
||||
|
||||
## Sponsor
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src=".github/jetbrains-variant-4.svg" alt="JetBrains" width="200"/></a>
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="images/jetbrains-variant-4.svg" alt="JetBrains" width="200"/></a>
|
||||
|
||||
- [RabbitHosts](https://rabbithosts.com/cart.php)
|
||||
- [ManSora](https://www.mansora.co/cart.php)
|
||||
@@ -46,7 +46,7 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
|
||||
## Screenshots
|
||||

|
||||

|
||||
|
||||
## Requirements
|
||||
- [.NET Framework 4.8 (Included in Windows 10 1903+)](https://dotnet.microsoft.com/download/dotnet-framework/net48)
|
||||
@@ -67,5 +67,6 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
|
||||
- [Privoxy](https://www.privoxy.org/)
|
||||
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
|
||||
- [NetFilter SDK](https://netfiltersdk.com/)
|
||||
- [pcap2socks](https://github.com/zhxie/pcap2socks)
|
||||
|
||||
[](https://starchart.cc/NetchX/Netch)
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
[](https://github.com/NetchX/Netch/actions)
|
||||
[](LICENSE)
|
||||
|
||||
游戏加速工具
|
||||
[文档网站](https://netch.org/) [常见问题](https://netch.org/#/docs/zh-CN/faq)
|
||||
|
||||
[网站](https://netch.org/)
|
||||
游戏加速工具
|
||||
|
||||
## TOC
|
||||
- [Netch](#Netch)
|
||||
@@ -17,8 +17,6 @@
|
||||
- [简介](#简介)
|
||||
- [赞助商](#赞助商)
|
||||
- [捐赠](#捐赠)
|
||||
- [新手入门](Quickstart.zh-CN.md)
|
||||
- [进阶用法](Advanced_Usage.zh-CN.md)
|
||||
- [依赖](#依赖)
|
||||
- [语言支持](#语言支持)
|
||||
|
||||
@@ -31,15 +29,12 @@ Netch 是一款 Windows 平台的开源游戏加速工具,Netch 可以实现
|
||||
- ShadowsocksR
|
||||
- Trojan
|
||||
- VMess
|
||||
- VLess
|
||||
- VLESS
|
||||
|
||||
与此同时 Netch 避免了 SSTap 的 NAT 问题 ,检查 NAT 类型即可知道是否有 NAT 问题。使用 SSTap 加速部分 P2P 联机,对 NAT 类型有要求的游戏时,可能会因为 NAT 类型严格遇到无法加入联机,或者其他影响游戏体验的情况
|
||||
|
||||
|
||||
需要更多特性请移步魔改仓库 [Netch-ForOwnUse](https://github.com/AmazingDM/Netch-ForOwnUse),
|
||||
|
||||
## 赞助商
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="../.github/jetbrains-variant-4.svg" alt="JetBrains" width="200"/></a>
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="images/jetbrains-variant-4.svg" alt="JetBrains" width="200"/></a>
|
||||
|
||||
- [RabbitHosts](https://rabbithosts.com/cart.php)
|
||||
- [ManSora](https://www.mansora.co/cart.php)
|
||||
@@ -48,16 +43,13 @@ Netch 是一款 Windows 平台的开源游戏加速工具,Netch 可以实现
|
||||
## 捐赠
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
|
||||
## 新手入门
|
||||
[新手入门教程](Quickstart.zh-CN.md)
|
||||
|
||||
## 进阶用法
|
||||
[进阶教程](Advanced_Usage.zh-CN.md)
|
||||
## 依赖
|
||||
- [.NET Framework 4.8 (Windows 10 1903+ 已包含)](https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net48-offline-installer)
|
||||
|
||||
## 语言支持
|
||||
Netch 支持多种语言,在启动时会根据系统语言选择自身语言。如果需要手动切换语言,可以在启动时加入命令行参数,命令行参数为目前支持的语言代码,可以去 [NetchTranslation/i18n](https://github.com/NetchX/NetchTranslation/tree/master/i18n) 文件夹下查看外部支持的语言代码文件。Netch 目前内置 en-US,zh-CN,外置 zh-TW。欢迎大家为 [NetchTranslation](https://github.com/NetchX/NetchTranslation) 提供其他语言的翻译
|
||||
Netch 内置 en-US 和 zh-CN,外置 zh-TW 等,默认根据系统语言选择语言。
|
||||
|
||||
[Netch 外置语言仓库](https://github.com/NetchX/NetchTranslation) ,欢迎提供其他语言的翻译
|
||||
|
||||
## 引用
|
||||
- [core](https://github.com/aiocloud/core)
|
||||
@@ -75,3 +67,4 @@ Netch 支持多种语言,在启动时会根据系统语言选择自身语言
|
||||
- [Privoxy](https://www.privoxy.org/)
|
||||
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
|
||||
- [NetFilter SDK](https://netfiltersdk.com/)
|
||||
- [pcap2socks](https://github.com/zhxie/pcap2socks)
|
||||
3
SearchComboBox/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
/bin
|
||||
/obj
|
||||
/SearchComboBox.csproj.user
|
||||
3
UnitTest/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
/bin
|
||||
/obj
|
||||
/Netch.csproj.user
|
||||
@@ -6,10 +6,10 @@ using Netch.Utils;
|
||||
namespace UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class FunctionTest : TestBase
|
||||
public class Function : TestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestLoadI18N()
|
||||
public void LoadLanguage()
|
||||
{
|
||||
void TestLoad(string t)
|
||||
{
|
||||
98
UnitTest/ParameterTest.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Netch.Models;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class ParameterTest
|
||||
{
|
||||
[Verb]
|
||||
private class VerbAndRealName : ParameterBase
|
||||
{
|
||||
[RealName("v")]
|
||||
public string v1 { get; } = "a";
|
||||
|
||||
[RealName("v")]
|
||||
public string v2 { get; } = "b";
|
||||
}
|
||||
|
||||
private class Full : ParameterBase
|
||||
{
|
||||
[RealName("f")]
|
||||
public string f1 { get; } = "a";
|
||||
|
||||
[RealName("f")]
|
||||
public string f2 { get; } = "b";
|
||||
}
|
||||
|
||||
private class FullWithVerb : ParameterBase
|
||||
{
|
||||
public string f { get; } = "a";
|
||||
|
||||
[Verb]
|
||||
public string v { get; } = "b";
|
||||
}
|
||||
|
||||
[Verb]
|
||||
private class VerbWithFull : ParameterBase
|
||||
{
|
||||
public string v { get; } = "a";
|
||||
|
||||
[Full]
|
||||
public string f { get; } = "b";
|
||||
}
|
||||
|
||||
private class QuoteValue : ParameterBase
|
||||
{
|
||||
public static string pathValue = @"C:\Programe Files\Damn thats space";
|
||||
|
||||
[Quote]
|
||||
public string path { get; set; } = pathValue;
|
||||
}
|
||||
|
||||
private class FlagAndOptional : ParameterBase
|
||||
{
|
||||
public bool a { get; set; } = true;
|
||||
|
||||
public bool b { get; set; } = false;
|
||||
|
||||
[Optional]
|
||||
public string c { get; set; } = string.Empty;
|
||||
|
||||
[Optional]
|
||||
public string? d { get; set; } = null;
|
||||
}
|
||||
|
||||
private class RequiredEmpty : ParameterBase
|
||||
{
|
||||
public string? udp { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
private class RequiredNull : ParameterBase
|
||||
{
|
||||
public string? udp { get; set; } = null;
|
||||
}
|
||||
|
||||
private class Number : ParameterBase
|
||||
{
|
||||
public ushort a { get; set; } = 1;
|
||||
|
||||
public int b { get; set; } = 1;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Test()
|
||||
{
|
||||
Assert.AreEqual(new VerbAndRealName().ToString(), "-v a -v b");
|
||||
Assert.AreEqual(new Full().ToString(), "--f a --f b");
|
||||
Assert.AreEqual(new FullWithVerb().ToString(), "--f a -v b");
|
||||
Assert.AreEqual(new VerbWithFull().ToString(), "-v a --f b");
|
||||
Assert.AreEqual(new QuoteValue().ToString(), $"--path \"{QuoteValue.pathValue}\"");
|
||||
Assert.AreEqual(new FlagAndOptional().ToString(), "--a");
|
||||
Assert.ThrowsException<RequiredArgumentValueInvalidException>(() => { _ = new RequiredEmpty().ToString(); });
|
||||
Assert.ThrowsException<RequiredArgumentValueInvalidException>(() => { _ = new RequiredNull().ToString(); });
|
||||
Assert.AreEqual(new Number().ToString(), "--a 1 --b 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,10 @@ using Netch.Utils;
|
||||
namespace UnitTest
|
||||
{
|
||||
[TestClass]
|
||||
public class TestParseShareLink : TestBase
|
||||
public class ParseShareLink : TestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestServerFromSSR()
|
||||
public void ParseSSR()
|
||||
{
|
||||
const string normalCase =
|
||||
"ssr://MTI3LjAuMC4xOjEyMzQ6YXV0aF9hZXMxMjhfbWQ1OmFlcy0xMjgtY2ZiOnRsczEuMl90aWNrZXRfYXV0aDpZV0ZoWW1KaS8_b2Jmc3BhcmFtPVluSmxZV3QzWVRFeExtMXZaUQ";
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
using Netch;
|
||||
|
||||
namespace UnitTest
|
||||
namespace UnitTest
|
||||
{
|
||||
public class TestBase
|
||||
{
|
||||
protected TestBase()
|
||||
{
|
||||
#if DEBUG
|
||||
Global.Testing = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -23,8 +24,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
2
binaries
@@ -1,213 +0,0 @@
|
||||
# Netch 模式
|
||||
|
||||
## 目录
|
||||
|
||||
1. [模式介绍](#模式介绍)
|
||||
- 1.1 [模式 1 进程代理模式](#模式-1-进程代理模式)
|
||||
- 1.2 [模式 2(需要自己新建模式文件) TUN/TAP IP 黑名单代理模式](#模式-2需要自己新建模式文件-tuntap-ip-黑名单代理模式)
|
||||
- 1.3 [模式 3 TUN/TAP (IP 白名单)全局代理模式](#模式-3-tuntap-ip-白名单全局代理模式)
|
||||
- 1.4 [模式 4 HTTP 系统代理](#模式-4-http-系统代理)
|
||||
- 1.5 [模式 5 本地 Socks5 代理](#模式-5-本地-socks5-代理)
|
||||
- 1.6 [模式 6 本地 Socks5 和 HTTP 代理](#模式-6-本地-socks5-和-http-代理)
|
||||
2. [Socks 5 代理中转](#socks-5-代理中转)
|
||||
3. [新建进程代理模式](#新建进程代理模式)
|
||||
- 3.1 [模式](#模式)
|
||||
- 3.2 [扫描](#扫描)
|
||||
- 3.3 [启动](#启动)
|
||||
|
||||
## 模式介绍
|
||||
|
||||
目前 Netch 所有模式文件都在 `mode` 文件夹下。模式号即模式菜单中最左边中括号内数字
|
||||
|
||||
内置的模式中,如果模式名中有 Bypass China 的部分,即该模式会绕过中国 IP 段
|
||||
|
||||
模式 1 和模式 2 里面除了第一行格式不同,其他内容和 [SSTap-Rule](https://github.com/FQrabbit/SSTap-Rule) 相同。是否绕过中国的功能依赖于 [CNIP 文件](https://github.com/NetchX/Netch/blob/master/Netch/Resources/CNIP)
|
||||
|
||||
模式 3 到模式 5 的是否绕过中国的功能依赖于 [acl 文件](https://github.com/NetchX/Netch/blob/master/binaries/default.acl)
|
||||
|
||||
第一行格式均为如下样式,不同模式之间第一行的具体区别可以参照后面的内容
|
||||
|
||||
```Python
|
||||
# 备注, 类型(是主项目 USAGE.zh-CN.md 里提到的模式类型的值减一), 是否绕过中国(1 为是, 0 为否)
|
||||
```
|
||||
|
||||
### 模式 1 进程代理模式
|
||||
|
||||
- 根据进程名进行代理
|
||||
- 底层依赖于 [NetFilter SDK](https://netfiltersdk.com)
|
||||
- 对于第一次使用 Netch 的用户而言,不需要做多余的事情
|
||||
- 若 [NetFilter SDK](https://netfiltersdk.com) 的驱动不存在,会自动安装
|
||||
- 若驱动版本过低,会自动更新
|
||||
|
||||
范例文件
|
||||
|
||||
在这个模式里,第一行只有备注是有用的,规则内容支持C++正则表达式
|
||||
|
||||
```
|
||||
# 备注
|
||||
进程名 1(会被代理)
|
||||
!进程名 2(不会被代理)
|
||||
csgo.exe
|
||||
\\steam\\(代理运行路径包含steam的所有程序)
|
||||
...
|
||||
```
|
||||
|
||||
### 模式 2(需要自己新建模式文件) TUN/TAP IP 黑名单代理模式
|
||||
|
||||
- 黑名单代理指的是,除了名单内的 IP 走代理,其他连接都不走代理
|
||||
- 需要自己新建模式文件,第一行写法同模式 3,只是需要把 2 改成 1
|
||||
- 后续内容的格式同 [SSTap-rules](https://github.com/FQrabbit/SSTap-Rule),任何规则问题建议到那边去提
|
||||
- 可以通过左下角的`设置`来配置 IP 地址,子网掩码,网关,DNS
|
||||
- 该模式下直连 IP 段无效,暂时没有代码实现
|
||||
- 底层依赖于 [Tap-Windows](https://github.com/OpenVPN/tap-windows) 适配器等
|
||||
- 如果 Netch 提示没有该适配器,可以直接安装 [Tap-Windows](https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe) 或者通过安装 [OpenVPN](https://openvpn.net/community-downloads/),[SSTap](https://github.com/mayunbaba2/SSTap-beta-setup) 的方式获得该适配器
|
||||
|
||||
范例文件
|
||||
|
||||
在这个模式里,是否绕过中国的值是无效的
|
||||
|
||||
```
|
||||
# 备注, 1
|
||||
无类别域间路由写法 1(目的 IP 在这个子网内的网络请求都会被代理)
|
||||
无类别域间路由写法 2
|
||||
...
|
||||
```
|
||||
|
||||
### 模式 3 TUN/TAP (IP 白名单)全局代理模式
|
||||
|
||||
- 白名单代理指的是,除了名单内的 IP 不走代理,其他连接都走代理
|
||||
- 可以通过左下角的`设置`来配置 IP 地址,子网掩码,网关,DNS,直连 IP 段
|
||||
- 底层依赖于 [Tap-Windows](https://github.com/OpenVPN/tap-windows) 适配器,tun2socks 等
|
||||
- 如果 Netch 提示没有该适配器,可以直接安装 [Tap-Windows](https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe) 或者通过安装 [OpenVPN](https://openvpn.net/community-downloads/),[SSTap](https://github.com/mayunbaba2/SSTap-beta-setup) 的方式获得该适配器
|
||||
|
||||
范例文件
|
||||
|
||||
```
|
||||
# 备注, 2, 是否绕过中国(1 为是, 0 为否)
|
||||
无类别域间路由写法 1(目的 IP 只有在这个子网内的网络请求不会被代理,其他的都会被代理)
|
||||
无类别域间路由写法 2
|
||||
...
|
||||
```
|
||||
|
||||
### 模式 4 HTTP 系统代理
|
||||
|
||||
- 默认地址和端口为 127.0.0.1:2802
|
||||
- 端口可以在左下角设置里面更改
|
||||
- 会被设置为系统代理
|
||||
|
||||
范例文件
|
||||
|
||||
```
|
||||
# 备注, 3, 是否绕过中国(1 为是, 0 为否)
|
||||
(目前只有第一行是有效的)
|
||||
```
|
||||
|
||||
### 模式 5 本地 Socks5 代理
|
||||
|
||||
- 默认地址和端口为 127.0.0.1:2801
|
||||
- 端口可以在左下角设置里面更改
|
||||
- 不会被设置为系统代理,对于 Chrome 之类使用系统代理的浏览器需要设置使用插件 SwitchyOmega 之后才能被正常代理
|
||||
- 注意如果是使用 Firefox 的网络设置,请仅设置 Socks5 代理,清除其他代理配置,并取消勾选`为所有协议使用相同的代理服务器`
|
||||
- 其他模式均含 Socks5 代理,本模式可以理解为仅 Socks5 代理\
|
||||
|
||||
范例文件
|
||||
|
||||
```
|
||||
# 备注, 4, 是否绕过中国(1 为是, 0 为否)
|
||||
(目前只有第一行是有效的)
|
||||
```
|
||||
|
||||
### 模式 6 本地 Socks5 和 HTTP 代理
|
||||
|
||||
- Socks5 代理的默认地址和端口为 127.0.0.1:2801
|
||||
- HTTP 代理的默认地址和端口为 127.0.0.1:2802
|
||||
- 端口可以在左下角设置里面更改
|
||||
- 不会被设置为系统代理
|
||||
|
||||
范例文件
|
||||
|
||||
```
|
||||
# 备注, 5, 是否绕过中国(1 为是, 0 为否)
|
||||
(目前只有第一行是有效的)
|
||||
```
|
||||
|
||||
## Socks 5 代理中转
|
||||
|
||||
说明一下,Netch 并非是以网页代理为目的开发的程序,如果需要网络代理为目的的程序,需要 PAC,规则分流,订阅管理等功能的,请尽量参考使用以下软件而非 Netch(均为 Windows 平台)
|
||||
|
||||
ShadowsocksR
|
||||
|
||||
- [HMBSbige/ShadowsocksR-Windows](https://github.com/HMBSbige/ShadowsocksR-Windows/releases)
|
||||
|
||||
Shadowsocks
|
||||
|
||||
- [Clash for Windows](https://github.com/Fndroid/clash_for_windows_pkg/releases)
|
||||
|
||||
V2Ray
|
||||
|
||||
- [V2RayN](https://github.com/2dust/v2rayN/releases)
|
||||
|
||||
如果你想使用的代理工具目前 Netch 还不支持,或者需要一些 Netch 目前没有的功能,如 V2Ray 自定义配置,Socks5 本地代理规则分流的,可以在 Netch 里添加对应工具的本地 Socks5 代理端口后使用,注意如果你用的是模式 3 TUN/TAP (IP 白名单)全局代理模式,记得在`设置 - 全局直连 IP`中添加你的服务器 IP 地址,否则会产生代理回环
|
||||
|
||||
## 新建进程代理模式
|
||||
|
||||
- 现在软件还处在早期开发阶段,可能后续版本会发生很大变化,操作仅供参考
|
||||
|
||||
当前版本已添加配置编辑功能,根据自己的情况,使用订阅或者别的方法添加代理配置,我这里使用的是剪贴板导入
|
||||
|
||||

|
||||
|
||||
如果你发现你的程序没我截图的看起来清晰,可以右键 `Netch.exe - 属性 - 兼容性 - 更改高 DPI 设置 - 替代高 DPI 缩放执行 - 系统(增强)`
|
||||
|
||||
### 模式
|
||||
|
||||
如果你的游戏的模式已经被收录,也可以考虑在模式菜单中,选择使用已收录的模式。所有模式的文件,都在 `./mode/` 文件夹下,如果你需要多个模式的合并文件,可以使用记事本将其打开,将多个文件合并
|
||||
|
||||
ping 的值未必准确,因为这只是你本地到代理服务器而非游戏服务器的延迟
|
||||
|
||||
如果你的游戏的模式没被收录,可以看接下来的扫描步骤来手动创建模式
|
||||
|
||||
接着点击菜单栏上的`模式 - 创建进程模式`
|
||||
|
||||

|
||||
|
||||
### 扫描
|
||||
|
||||
在弹出的窗口中点击`扫描`
|
||||
|
||||

|
||||
|
||||
选择你要加速的游戏的安装路径,根据游戏不同,可能需要选择多个不同的目录进行扫描,参见[萌鹰的 Netch 教程](https://www.eaglemoe.com/archives/142)(包括 GTAOL 和 R6S 的配置方法)
|
||||
|
||||
>4. 选定 GTA5 游戏目录,点击确定,软件会自动扫描目录下的 exe 程式并填写进去
|
||||
>5. 再次点击扫描,选择 SocialClub 的安装地址(一般为 C:\Program Files\Rockstar Games\Social Club),点击确定,点击保存
|
||||
>
|
||||
>注意:加入游戏时请不要忘记加入社交组件,比如说 GTA 不要忘记 SocialClub ,彩虹六号不要忘记 Uplay,如果游戏进程名与其他进程名重复,则可手动修改已创建好的模式文件,在进程名前加上绝对路径即可。csgo.exe -> C:\steam\game\Counter-Strike Global Offensive\csgo.exe
|
||||
|
||||
这里以CSGO为例,只需添加CSGO游戏根目录即可
|
||||
|
||||

|
||||
|
||||
扫描时可能需要稍等片刻,扫描后记得填写备注
|
||||
|
||||
如果需要添加单个程序,也可以在添加按钮左侧的编辑栏中手动输入并添加
|
||||
|
||||
之后点保存进行`保存`
|
||||
|
||||

|
||||
|
||||
### 启动
|
||||
|
||||
最后确认服务器一栏和模式一栏均为之前自己添加并需要使用的,没问题后点击`启动`即可
|
||||
|
||||

|
||||
|
||||
启动后,你再去游戏根目录或者别的启动器如 Steam,Uplay 启动游戏即可。此时游戏就已经被代理了
|
||||
|
||||
如果在 Netch 启动前就启动了游戏,建议重启游戏
|
||||
|
||||
如果需要 Steam,Uplay 等启动器也被代理,参照前面的方式对 Steam,Uplay 根目录也进行扫描即可
|
||||
|
||||
## 语言支持
|
||||
|
||||
Netch 支持多种语言,在启动时会根据系统语言选择自身语言。如果需要手动切换语言,可以在启动时加入命令行参数,命令行参数为目前支持的语言代码,可以去 [NetchTranslation/i18n](https://github.com/NetchX/NetchTranslation/tree/master/i18n) 文件夹下查看外部支持的语言代码文件。Netch 目前内置 en-US,zh-CN,外置 zh-TW。欢迎大家为 [NetchTranslation](https://github.com/NetchX/NetchTranslation) 提供其他语言的翻译
|
||||
@@ -1,48 +0,0 @@
|
||||
# 新手入门
|
||||
**Version : 1.5.1**
|
||||
|
||||
[下载地址](https://github.com/NetchX/Netch/releases)
|
||||
|
||||
## 主界面
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 设置界面
|
||||
|
||||

|
||||
|
||||
## 添加服务器
|
||||
|
||||
> Netch 目前仅支持以下代理协议:Shadowsocks,VMess,Socks5,ShadowsockR,Trojan。
|
||||
|
||||
首先,点击`服务器`增加所需服务器
|
||||
|
||||
<img width="80%" height="80%" src="screenshots/addServer.zh-CN.png">
|
||||
|
||||
可手动添加单个服务器,或者通过剪切板链接添加单个服务器。也可通过订阅链接批量添加。
|
||||
|
||||
点击 `订阅` ` 管理订阅链接` 进入以下界面。
|
||||
|
||||
<img width="80%" height="80%" src="screenshots/addLink.zh-CN.png">
|
||||
|
||||
填写备注与链接,然后保存即可。保存后在主界面点击 `订阅` ` 从订阅链接更新服务器`。完成服务器添加。添加完服务器后可对服务器进行修改,删除和测速。
|
||||
|
||||
## 选择模式
|
||||
|
||||
> 此处需要会一点英语,比如你应该知道 `吃鸡` 的英文名称是 `PlayerUnknown's Battlegrounds`
|
||||
|
||||
模式选择框有搜索功能,在模式框里输入字符即可搜索,使用英文名称进行搜索,搜索到所需的模式后单击选择,启用模式。相对应的游戏即可被加速
|
||||
|
||||
若没有所需的模式,请选择 `[3] Bypass LAN and China (TUN/TAP)` 的模式。此模式需要安装 [TAP-Windows](https://github.com/OpenVPN/tap-windows) 适配器,如果 Netch 提示没有该适配器,可以直接安装 [TAP-Windows](https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe) 来获得该适配器
|
||||
|
||||
关于更多的模式说明,详见 [进阶用法](Advanced_Usage.zh-CN.md)。
|
||||
|
||||
选择完模式后,点击启用,游戏已被代理。这一步需在开启游戏前完成。
|
||||
|
||||
## 配置说明
|
||||
|
||||
在设置界面填写完快捷配置数量后即可在主界面进行配置,填入配置名,选择相应的服务器和游戏模式,按下 `Ctrl` 与鼠标左键,即可保存当前配置。下次使用时,点击配置名即可快速启用。
|
||||
|
||||
~~ 如果你还觉得不会用,可以去用 SSTap (逃~~
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |