mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
76 Commits
1.8.3-Beta
...
1.8.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63f51a481c | ||
|
|
e89c742f3f | ||
|
|
458c6047af | ||
|
|
561def7fe1 | ||
|
|
9e68fb12fb | ||
|
|
d7360b3688 | ||
|
|
7844c183e7 | ||
|
|
8325bd1fe3 | ||
|
|
0a59d6aa3f | ||
|
|
7fa05e7dad | ||
|
|
b948040f9d | ||
|
|
0c76198bd4 | ||
|
|
d917e5a8fa | ||
|
|
015e4ada94 | ||
|
|
86b1741dd0 | ||
|
|
4af18025a7 | ||
|
|
3678c98fec | ||
|
|
9f809b4d27 | ||
|
|
e3a3396d18 | ||
|
|
43c19c6698 | ||
|
|
9ee2a2a31a | ||
|
|
489c3fc39d | ||
|
|
657266df47 | ||
|
|
82ed5189c8 | ||
|
|
ebe2978724 | ||
|
|
764d42efe2 | ||
|
|
8b81df03c4 | ||
|
|
4cc5998440 | ||
|
|
2051dd1bfe | ||
|
|
b167674d37 | ||
|
|
74caeeaf42 | ||
|
|
60dd3c8965 | ||
|
|
ee2d35cb5d | ||
|
|
6f6ff85549 | ||
|
|
9a8c4d6093 | ||
|
|
00268d67fa | ||
|
|
b1f89c177d | ||
|
|
4a543dcf1a | ||
|
|
5b5262e03e | ||
|
|
60f0637b03 | ||
|
|
460d295a66 | ||
|
|
ccd46144ab | ||
|
|
84e481f704 | ||
|
|
fb64951003 | ||
|
|
258880ef95 | ||
|
|
2bda0bdf8e | ||
|
|
bc0e5d0dcf | ||
|
|
4e4af89fbe | ||
|
|
1e9ff83aa2 | ||
|
|
a4d8619944 | ||
|
|
0bb54abe6c | ||
|
|
0ad18ee566 | ||
|
|
80460c0a21 | ||
|
|
098680482e | ||
|
|
16d7f53ee3 | ||
|
|
ed946c44a2 | ||
|
|
62c28ccab2 | ||
|
|
a2326389db | ||
|
|
b0086cc854 | ||
|
|
d2548d2893 | ||
|
|
101d8c5a25 | ||
|
|
1b36b707f6 | ||
|
|
a94bf0d53d | ||
|
|
32a9261041 | ||
|
|
2b0530d9b0 | ||
|
|
2d85e78b77 | ||
|
|
b8b4dbfb0a | ||
|
|
025eda8286 | ||
|
|
44da2e8011 | ||
|
|
54daff70b3 | ||
|
|
b218e785d8 | ||
|
|
5b857cc518 | ||
|
|
4693025576 | ||
|
|
46eefd3db9 | ||
|
|
eb1ee9e820 | ||
|
|
b501ed38c4 |
@@ -12,6 +12,7 @@ tab_width = 4
|
||||
# Microsoft .NET properties
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
|
||||
csharp_space_after_cast = false
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
@@ -27,7 +28,7 @@ dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
# ReSharper properties
|
||||
resharper_align_multiline_switch_expression = true
|
||||
resharper_align_multiline_switch_expression = false
|
||||
resharper_align_multline_type_parameter_constrains = true
|
||||
resharper_blank_lines_after_block_statements = 0
|
||||
resharper_blank_lines_after_multiline_statements = 1
|
||||
@@ -73,7 +74,7 @@ resharper_place_simple_initializer_on_single_line = true
|
||||
resharper_place_simple_switch_expression_on_single_line = true
|
||||
resharper_show_autodetect_configure_formatting_tip = false
|
||||
resharper_space_around_arrow_op = true
|
||||
resharper_space_within_single_line_array_initializer_braces = false
|
||||
resharper_space_within_single_line_array_initializer_braces = true
|
||||
resharper_use_indent_from_vs = false
|
||||
resharper_wrap_array_initializer_style = wrap_if_long
|
||||
resharper_wrap_before_arrow_with_expressions = true
|
||||
|
||||
32
.github/ISSUE_TEMPLATE/bug_report.md.off
vendored
32
.github/ISSUE_TEMPLATE/bug_report.md.off
vendored
@@ -1,32 +0,0 @@
|
||||
---
|
||||
name: 'Bug report'
|
||||
about: 'Create a report to help us improve'
|
||||
title: ''
|
||||
labels: '需要核实'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Open Netch
|
||||
2. ...
|
||||
|
||||
**Log**
|
||||
Attaching any log files in the folder `Netch\logging` is strongly recommended.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
- OS: [e.g. Windows 10 Pro 64-bit 1903]
|
||||
- Netch Version: [e.g. 1.0.0-STABLE.x64]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
28
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
28
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,12 +1,7 @@
|
||||
name: Bug report
|
||||
description: "Create a report to help us improve"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
description: Create a report to help us improve
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**"
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
@@ -19,7 +14,6 @@ body:
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
placeholder: |
|
||||
Steps to reproduce the behavior:
|
||||
1. Open Netch
|
||||
2. ...
|
||||
validations:
|
||||
@@ -30,26 +24,28 @@ body:
|
||||
label: CAPTCHA
|
||||
description: Please confirm the options below.
|
||||
options:
|
||||
- label: I am human
|
||||
- label: Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
render: shell
|
||||
label: Log
|
||||
description: Attaching any log files in the folder `Netch\logging` is strongly recommended.
|
||||
description: Attaching any log files in the folder `logging` is strongly recommended.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
render: txt
|
||||
placeholder: |
|
||||
- OS: [e.g. Windows 10 Pro 64-bit 1903]
|
||||
- Netch Version: [e.g. 1.0.0-STABLE.x64]
|
||||
- OS: [e.g. Windows 10 x64 Professional Workstation 20H2 19042.928]
|
||||
- Netch Version: [e.g. 1.0.0]
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
value: |
|
||||
In the text box below, you can attach any relevant screenshots and files.
|
||||
label: Additional information
|
||||
description: >
|
||||
If you have any additional information for us, use the field below.
|
||||
|
||||
29
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md.off
vendored
29
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md.off
vendored
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: '错误报告'
|
||||
about: '创建错误报告以帮助我们改进'
|
||||
title: ''
|
||||
labels: '需要核实'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
|
||||
|
||||
**错误描述**
|
||||
对错误的清晰简洁描述
|
||||
|
||||
**复现步骤**
|
||||
1. 打开 Netch 软件
|
||||
2. ...
|
||||
|
||||
**日志**
|
||||
强烈建议附上任何在 `Netch\logging` 文件夹下面的日志。
|
||||
|
||||
**错误截图**
|
||||
如果适用,请添加屏幕截图以帮助解释您的问题
|
||||
|
||||
**信息**
|
||||
- 操作系统:[例如 Windows 10 专业版 64 位 1903]
|
||||
- 软件版本:[例如 1.0.0-STABLE 64 位]
|
||||
|
||||
**额外信息**
|
||||
35
.github/ISSUE_TEMPLATE/bug_report.zh-CN.yml
vendored
35
.github/ISSUE_TEMPLATE/bug_report.zh-CN.yml
vendored
@@ -1,54 +1,43 @@
|
||||
name: 错误报告
|
||||
description: "创建错误报告以帮助我们改进"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
description: 创建错误报告以帮助我们改进
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**"
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: "错误描述"
|
||||
label: 错误描述
|
||||
description: 对错误的清晰简洁描述
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: "复现步骤"
|
||||
label: 复现步骤
|
||||
placeholder: |
|
||||
1. 打开 Netch 软件
|
||||
2. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: captcha
|
||||
attributes:
|
||||
label: 验证
|
||||
description: 请确认下面选项
|
||||
options:
|
||||
- label: 我是人类
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
render: shell
|
||||
label: 日志
|
||||
description: 强烈建议附上任何在 `Netch\logging` 文件夹下面的日志
|
||||
description: 强烈建议附上任何在 `logging` 文件夹下面的日志
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: 操作环境
|
||||
render: txt
|
||||
placeholder: |
|
||||
操作系统:[Windows 10 专业版 64 位 1903]
|
||||
软件版本:[1.0.0-STABLE 64 位]
|
||||
操作系统:[Windows 10 x64 Professional Workstation 20H2 19042.928]
|
||||
软件版本:[1.0.0]
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
value: |
|
||||
label: 额外信息
|
||||
description: >
|
||||
下面的文本框中你可以附上跟 issue 相关的截图、文件
|
||||
|
||||
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,9 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Telegram Channel
|
||||
url: https://t.me/Netch
|
||||
url: https://t.me/netch_channel
|
||||
about: Telegram Channel
|
||||
|
||||
- name: Telegram Group
|
||||
url: https://t.me/Netch_Discuss_Group
|
||||
about: Telegram Group
|
||||
url: https://t.me/netch_group
|
||||
about: Telegram Group
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/feature_request.md.off
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md.off
vendored
@@ -1,16 +0,0 @@
|
||||
---
|
||||
name: 'Feature request'
|
||||
about: 'Suggest an idea for this project'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
|
||||
|
||||
**Describe the feature you want**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Additional context** (Optional)
|
||||
Add any other context or screenshots about the feature request here.
|
||||
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,16 +1,11 @@
|
||||
name: request
|
||||
description: "Suggest an idea for this project"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
name: Feature request
|
||||
description: Suggest an idea for this project
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Describe the feature you want"
|
||||
label: Describe the feature you want
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
name: '功能请求'
|
||||
about: '建议这个项目的想法'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
|
||||
|
||||
**功能描述**
|
||||
简明扼要地描述需要的功能
|
||||
|
||||
**额外信息**
|
||||
11
.github/ISSUE_TEMPLATE/feature_request.zh-CN.yml
vendored
11
.github/ISSUE_TEMPLATE/feature_request.zh-CN.yml
vendored
@@ -1,16 +1,11 @@
|
||||
name: 功能请求
|
||||
description: "建议这个项目的想法"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
description: 建议这个项目的想法
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "功能描述"
|
||||
label: 功能描述
|
||||
description: 简明扼要地描述需要的功能
|
||||
validations:
|
||||
required: true
|
||||
|
||||
27
.github/dependabot.yml
vendored
27
.github/dependabot.yml
vendored
@@ -1,34 +1,21 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "07:00"
|
||||
time: "00:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- "automatic"
|
||||
open-pull-requests-limit: 114514
|
||||
|
||||
- package-ecosystem: "nuget"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "07:15"
|
||||
time: "00:10"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "07:15"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- "automatic"
|
||||
open-pull-requests-limit: 114514
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
files: |
|
||||
Netch.7z
|
||||
body: |
|
||||
[](https://t.me/Netch) [](https://t.me/Netch_Discuss_Group)
|
||||
[](https://t.me/netch_channel) [](https://t.me/netch_group)
|
||||
|
||||
## 更新日志
|
||||
* 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
{
|
||||
public const string Show = "-show";
|
||||
public const string ForceUpdate = "-forceUpdate";
|
||||
public const string Console = "-console";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using static Netch.Interops.AioDNSInterops;
|
||||
using Netch.Interfaces;
|
||||
using static Netch.Interops.AioDNS;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -8,6 +9,8 @@ namespace Netch.Controllers
|
||||
{
|
||||
public string Name { get; } = "DNS Service";
|
||||
|
||||
private const string RulePath = "bin\\aiodns.conf";
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Free();
|
||||
@@ -21,7 +24,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
Dial(NameList.TYPE_REST, "");
|
||||
Dial(NameList.TYPE_ADDR, $"{Global.Settings.LocalAddress}:{Global.Settings.AioDNS.ListenPort}");
|
||||
Dial(NameList.TYPE_LIST, Path.GetFullPath(Global.Settings.AioDNS.RulePath));
|
||||
Dial(NameList.TYPE_LIST, Path.GetFullPath(RulePath));
|
||||
Dial(NameList.TYPE_CDNS, $"{Global.Settings.AioDNS.ChinaDNS}");
|
||||
Dial(NameList.TYPE_ODNS, $"{Global.Settings.AioDNS.OtherDNS}");
|
||||
|
||||
|
||||
@@ -199,15 +199,22 @@ namespace Netch.Controllers
|
||||
_logStreamWriter!.WriteLine(line);
|
||||
}
|
||||
|
||||
private readonly object LogStreamLock = new();
|
||||
private void CloseLogFile()
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_flushFileStreamTimer.Enabled = false;
|
||||
_logStreamWriter?.Close();
|
||||
_logFileStream?.Close();
|
||||
_logStreamWriter = _logStreamWriter = null;
|
||||
lock (LogStreamLock)
|
||||
{
|
||||
if (_logFileStream == null)
|
||||
return;
|
||||
|
||||
_flushFileStreamTimer.Enabled = false;
|
||||
_logStreamWriter?.Close();
|
||||
_logFileStream?.Close();
|
||||
_logStreamWriter = _logStreamWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -54,7 +55,7 @@ namespace Netch.Controllers
|
||||
|
||||
public static void Start(Server server, Mode mode)
|
||||
{
|
||||
Global.Logger.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
Global.Logger.Info($"启动主控制器: {server.Type} [{(int)mode.Type}]{mode.Remark}");
|
||||
Server = server;
|
||||
Mode = mode;
|
||||
|
||||
@@ -186,16 +187,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
|
||||
{
|
||||
string fileName;
|
||||
try
|
||||
{
|
||||
fileName = p.MainModule?.FileName ?? throw new Exception(); // TODO what's this exception?
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Warning(e.ToString());
|
||||
var fileName = p.MainModule?.FileName;
|
||||
if (fileName == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileName.StartsWith(Global.NetchDir))
|
||||
{
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using static Netch.Interops.RedirectorInterop;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using static Netch.Interops.Redirector;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -148,7 +149,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
var invalidList = new List<string>();
|
||||
foreach (var s in mode.FullRule)
|
||||
foreach (var s in mode.GetRules())
|
||||
{
|
||||
if (s.StartsWith("!"))
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace Netch.Controllers
|
||||
/// 启动 NatTypeTester
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<(string?, string?, string?)> Start()
|
||||
public async Task<(string? result, string? localEnd, string? publicEnd)> Start()
|
||||
{
|
||||
string? localEnd = null, publicEnd = null, result = null, bindingTest = null;
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace Netch.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), $"{output}\r\n{error}");
|
||||
await File.WriteAllTextAsync(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), $"{output}\r\n{error}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -19,8 +21,6 @@ namespace Netch.Controllers
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "└" };
|
||||
|
||||
private readonly OutboundAdapter _outbound = new();
|
||||
|
||||
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
private LogForm? _form;
|
||||
@@ -32,13 +32,15 @@ namespace Netch.Controllers
|
||||
_form = new LogForm(Global.MainForm);
|
||||
_form.CreateControl();
|
||||
|
||||
var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}");
|
||||
var outboundNetworkInterface = NetworkInterfaceUtils.GetBest();
|
||||
|
||||
var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.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"}");
|
||||
argument.Append($" {mode.GetRules().FirstOrDefault() ?? "-P n"}");
|
||||
StartInstanceAuto(argument.ToString());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,46 @@
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using static Netch.Interops.TUNInterop;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using Netch.Interops;
|
||||
using static Netch.Interops.tun2socks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNController : IModeController
|
||||
{
|
||||
private readonly List<string> _directIPs = new();
|
||||
public string Name => "tun2socks";
|
||||
|
||||
private readonly List<string> _proxyIPs = new();
|
||||
private const string DummyDns = "6.6.6.6";
|
||||
|
||||
public readonly DNSController DNSController = new();
|
||||
private readonly DNSController _aioDnsController = new();
|
||||
|
||||
public string Name { get; } = "tun2socks";
|
||||
private NetRoute _outbound;
|
||||
|
||||
private NetRoute _tun;
|
||||
|
||||
private readonly OutboundAdapter _outboundAdapter = new();
|
||||
private IAdapter _tunAdapter = null!;
|
||||
private IPAddress _serverAddresses = null!;
|
||||
|
||||
private Mode _mode = null!;
|
||||
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
_mode = mode;
|
||||
var server = MainController.Server!;
|
||||
_serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start
|
||||
|
||||
IPAddress address;
|
||||
(_outbound, address) = NetRoute.GetBestRouteTemplate();
|
||||
CheckDriver();
|
||||
|
||||
Dial(NameList.TYPE_ADAPMTU, "1500");
|
||||
Dial(NameList.TYPE_BYPBIND, _outboundAdapter.Address.ToString());
|
||||
Dial(NameList.TYPE_BYPBIND, address.ToString());
|
||||
Dial(NameList.TYPE_BYPLIST, "disabled");
|
||||
|
||||
#region Server
|
||||
@@ -78,32 +84,111 @@ namespace Netch.Controllers
|
||||
else
|
||||
{
|
||||
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
|
||||
DNSController.Start();
|
||||
_aioDnsController.Start();
|
||||
Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Global.Logger.Debug("tun2socks init");
|
||||
Init();
|
||||
if (!Init())
|
||||
throw new MessageException("tun2socks start failed, reboot your system and start again.");
|
||||
|
||||
_tunAdapter = new TunAdapter();
|
||||
var tunIndex = (int)RouteHelper.ConvertLuidToIndex(tun_luid());
|
||||
_tun = NetRoute.TemplateBuilder(Global.Settings.TUNTAP.Gateway, tunIndex);
|
||||
|
||||
NativeMethods.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
Global.Settings.TUNTAP.Address,
|
||||
(byte)Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
|
||||
_tunAdapter.InterfaceIndex);
|
||||
(ulong)tunIndex);
|
||||
|
||||
SetupRouteTable(mode);
|
||||
}
|
||||
|
||||
private readonly string BinDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll");
|
||||
private readonly string SysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
|
||||
#region Route
|
||||
|
||||
private void SetupRouteTable(Mode mode)
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.Translate("Setup Route Table Rule"));
|
||||
Global.Logger.Info("设置路由规则");
|
||||
|
||||
// Server Address
|
||||
if (!IPAddress.IsLoopback(_serverAddresses))
|
||||
RouteUtils.CreateRoute(_outbound.FillTemplate(_serverAddresses.ToString(), 32));
|
||||
|
||||
// Global Bypass IPs
|
||||
RouteUtils.CreateRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs);
|
||||
|
||||
var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex);
|
||||
switch (mode.Type)
|
||||
{
|
||||
case ModeType.ProxyRuleIPs:
|
||||
// rules
|
||||
RouteUtils.CreateRouteFill(_tun, mode.GetRules());
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
tunNetworkInterface.SetDns(DummyDns);
|
||||
// proxy dummy dns
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32));
|
||||
|
||||
if (!Global.Settings.TUNTAP.UseCustomDNS)
|
||||
// proxy AioDNS other dns
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32));
|
||||
}
|
||||
|
||||
break;
|
||||
case ModeType.BypassRuleIPs:
|
||||
RouteUtils.CreateRouteFill(_outbound, mode.GetRules());
|
||||
|
||||
tunNetworkInterface.SetDns(DummyDns);
|
||||
|
||||
if (!Global.Settings.TUNTAP.UseCustomDNS)
|
||||
// bypass AioDNS other dns
|
||||
RouteUtils.CreateRoute(_outbound.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32));
|
||||
|
||||
NetworkInterfaceUtils.SetInterfaceMetric(_tun.InterfaceIndex, 0);
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate("0.0.0.0", 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearRouteTable()
|
||||
{
|
||||
if (!IPAddress.IsLoopback(_serverAddresses))
|
||||
RouteUtils.DeleteRoute(_outbound.FillTemplate(_serverAddresses.ToString(), 32));
|
||||
|
||||
RouteUtils.DeleteRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs);
|
||||
|
||||
switch (_mode.Type)
|
||||
{
|
||||
case ModeType.BypassRuleIPs:
|
||||
RouteUtils.DeleteRouteFill(_outbound, _mode.GetRules());
|
||||
NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(Free),
|
||||
Task.Run(ClearRouteTable),
|
||||
Task.Run(_aioDnsController.Stop)
|
||||
};
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
private void CheckDriver()
|
||||
{
|
||||
var binHash = Utils.Utils.SHA256CheckSum(BinDriver);
|
||||
var sysHash = Utils.Utils.SHA256CheckSum(SysDriver);
|
||||
string binDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll");
|
||||
string sysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
|
||||
|
||||
var binHash = Utils.Utils.SHA256CheckSum(binDriver);
|
||||
var sysHash = Utils.Utils.SHA256CheckSum(sysDriver);
|
||||
Global.Logger.Info("自带 wintun.dll Hash: " + binHash);
|
||||
Global.Logger.Info("系统 wintun.dll Hash: " + sysHash);
|
||||
if (binHash == sysHash)
|
||||
@@ -111,7 +196,8 @@ namespace Netch.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(BinDriver, SysDriver, true);
|
||||
Global.Logger.Info("Copy wintun.dll to System Directory");
|
||||
File.Copy(binDriver, sysDriver, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -119,190 +205,5 @@ namespace Netch.Controllers
|
||||
throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(Free),
|
||||
Task.Run(ClearRouteTable),
|
||||
Task.Run(DNSController.Stop)
|
||||
};
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置绕行规则
|
||||
/// </summary>
|
||||
/// <returns>是否设置成功</returns>
|
||||
private void SetupRouteTable(Mode mode)
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
|
||||
Global.Logger.Info("设置路由规则");
|
||||
|
||||
Global.Logger.Info("绕行 → 服务器 IP");
|
||||
if (!IPAddress.IsLoopback(_serverAddresses))
|
||||
RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound);
|
||||
|
||||
Global.Logger.Info("绕行 → 全局绕过 IP");
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.BypassIPs, RouteType.Outbound);
|
||||
|
||||
#region Rule IPs
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 1:
|
||||
// 代理规则 IP
|
||||
Global.Logger.Info("代理 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
Global.Logger.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.HijackDNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
|
||||
else
|
||||
RouteAction(Action.Create, $"{Global.Settings.AioDNS.OtherDNS}/32", RouteType.TUNTAP);
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
// 绕过规则 IP
|
||||
|
||||
Global.Logger.Info("绕行 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
|
||||
break;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (mode.Type == 2)
|
||||
{
|
||||
Global.Logger.Info("代理 → 全局");
|
||||
SetInterface(RouteType.TUNTAP, 0);
|
||||
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP, record: false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetInterface(RouteType routeType, int? metric = null)
|
||||
{
|
||||
var adapter = routeType == RouteType.Outbound ? _outboundAdapter : _tunAdapter;
|
||||
|
||||
var arguments = $"interface ip set interface {adapter.InterfaceIndex} ";
|
||||
if (metric != null)
|
||||
arguments += $"metric={metric} ";
|
||||
|
||||
Utils.Utils.ProcessRunHiddenAsync("netsh", arguments).Wait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除绕行规则
|
||||
/// </summary>
|
||||
private bool ClearRouteTable()
|
||||
{
|
||||
var mode = MainController.Mode!;
|
||||
RouteAction(Action.Delete, _directIPs, RouteType.Outbound);
|
||||
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
|
||||
_directIPs.Clear();
|
||||
_proxyIPs.Clear();
|
||||
if (mode.Type == 2)
|
||||
{
|
||||
SetInterface(RouteType.Outbound);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Package
|
||||
|
||||
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0, bool record = true)
|
||||
{
|
||||
foreach (var address in ipNetworks)
|
||||
RouteAction(action, address, routeType, metric);
|
||||
}
|
||||
|
||||
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0, bool record = true)
|
||||
{
|
||||
#region
|
||||
|
||||
if (!TryParseIPNetwork(ipNetwork, out var ip, out var cidr))
|
||||
return false;
|
||||
|
||||
IAdapter adapter = routeType switch
|
||||
{
|
||||
RouteType.Outbound => _outboundAdapter,
|
||||
RouteType.TUNTAP => _tunAdapter,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
|
||||
};
|
||||
|
||||
List<string> ipList = routeType switch
|
||||
{
|
||||
RouteType.Outbound => _directIPs,
|
||||
RouteType.TUNTAP => _proxyIPs,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
|
||||
};
|
||||
|
||||
string gateway = adapter.Gateway.ToString();
|
||||
var index = adapter.InterfaceIndex;
|
||||
|
||||
#endregion
|
||||
|
||||
bool result;
|
||||
switch (action)
|
||||
{
|
||||
case Action.Create:
|
||||
result = NativeMethods.CreateRoute(AddressFamily.InterNetwork, ip, (byte)cidr, gateway, index, metric);
|
||||
if (result && record)
|
||||
ipList.Add(ipNetwork);
|
||||
|
||||
break;
|
||||
case Action.Delete:
|
||||
result = NativeMethods.DeleteRoute(AddressFamily.InterNetwork, ip, (byte)cidr, gateway, index, metric);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(action), action, null);
|
||||
}
|
||||
|
||||
Global.Logger.Debug($"{action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})");
|
||||
if (!result)
|
||||
Global.Logger.Warning($"Failed to invoke {action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TryParseIPNetwork(string ipNetwork, out string ip, out int cidr)
|
||||
{
|
||||
ip = null!;
|
||||
cidr = 0;
|
||||
|
||||
var s = ipNetwork.Split('/');
|
||||
if (s.Length != 2)
|
||||
{
|
||||
Global.Logger.Warning($"Failed to parse rule {ipNetwork}");
|
||||
return false;
|
||||
}
|
||||
|
||||
ip = s[0];
|
||||
cidr = int.Parse(s[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum RouteType
|
||||
{
|
||||
Outbound,
|
||||
TUNTAP
|
||||
}
|
||||
|
||||
private enum Action
|
||||
{
|
||||
Create,
|
||||
Delete
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ namespace Netch.Controllers
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2021";
|
||||
|
||||
public const string AssemblyVersion = @"1.8.3";
|
||||
private const string Suffix = @"Beta1145141919";
|
||||
public const string AssemblyVersion = @"1.8.5";
|
||||
private const string Suffix = @"";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
|
||||
10
Netch/Enums/Modes.cs
Normal file
10
Netch/Enums/Modes.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Netch.Enums
|
||||
{
|
||||
public enum ModeType
|
||||
{
|
||||
Process = 0,
|
||||
ProxyRuleIPs = 1,
|
||||
BypassRuleIPs = 2,
|
||||
Pcap2Socks = 6
|
||||
}
|
||||
}
|
||||
10
Netch/Forms/MainForm.Designer.cs
generated
10
Netch/Forms/MainForm.Designer.cs
generated
@@ -43,6 +43,7 @@
|
||||
this.CleanDNSCacheToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ShowHideConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.HelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CheckForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.fAQToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -190,6 +191,7 @@
|
||||
//
|
||||
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.OpenDirectoryToolStripMenuItem,
|
||||
this.ShowHideConsoleToolStripMenuItem,
|
||||
this.CleanDNSCacheToolStripMenuItem,
|
||||
this.UninstallServiceToolStripMenuItem,
|
||||
this.removeNetchFirewallRulesToolStripMenuItem});
|
||||
@@ -226,6 +228,13 @@
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Text = "Remove Netch Firewall Rules";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Click += new System.EventHandler(this.RemoveNetchFirewallRulesToolStripMenuItem_Click);
|
||||
//
|
||||
// ShowHideConsoleToolStripMenuItem
|
||||
//
|
||||
this.ShowHideConsoleToolStripMenuItem.Name = "ShowHideConsoleToolStripMenuItem";
|
||||
this.ShowHideConsoleToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.ShowHideConsoleToolStripMenuItem.Text = "Show/Hide Console";
|
||||
this.ShowHideConsoleToolStripMenuItem.Click += new System.EventHandler(this.ShowHideConsoleToolStripMenuItem_Click);
|
||||
//
|
||||
// HelpToolStripMenuItem
|
||||
//
|
||||
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@@ -782,5 +791,6 @@
|
||||
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
|
||||
private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
@@ -14,18 +14,15 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Services;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Hide();
|
||||
new Route().ShowDialog();
|
||||
Show();
|
||||
}
|
||||
|
||||
#region Start
|
||||
|
||||
private readonly Dictionary<string, object> _mainFormText = new();
|
||||
@@ -47,8 +44,6 @@ namespace Netch.Forms
|
||||
|
||||
// 监听电源事件
|
||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
||||
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
}
|
||||
|
||||
private void AddAddServerToolStripMenuItems()
|
||||
@@ -60,7 +55,8 @@ namespace Netch.Forms
|
||||
{
|
||||
Name = $"Add{fullName}ServerToolStripMenuItem",
|
||||
Size = new Size(259, 22),
|
||||
Text = i18N.TranslateFormat("Add [{0}] Server", fullName)
|
||||
Text = i18N.TranslateFormat("Add [{0}] Server", fullName),
|
||||
Tag = serversUtil
|
||||
};
|
||||
|
||||
_mainFormText.Add(control.Name, new[] { "Add [{0}] Server", fullName });
|
||||
@@ -89,23 +85,23 @@ namespace Netch.Forms
|
||||
// 加载快速配置
|
||||
LoadProfiles();
|
||||
|
||||
Task.Run(() =>
|
||||
BeginInvoke(new Action(async () =>
|
||||
{
|
||||
// 检查更新
|
||||
if (Global.Settings.CheckUpdateWhenOpened)
|
||||
CheckUpdate();
|
||||
});
|
||||
await CheckUpdate();
|
||||
}));
|
||||
|
||||
Task.Run(() =>
|
||||
BeginInvoke(new Action(async () =>
|
||||
{
|
||||
// 检查订阅更新
|
||||
if (Global.Settings.UpdateServersWhenOpened)
|
||||
UpdateServersFromSubscribe().Wait();
|
||||
await UpdateServersFromSubscribe();
|
||||
|
||||
// 打开软件时启动加速,产生开始按钮点击事件
|
||||
if (Global.Settings.StartWhenOpened)
|
||||
ControlButton_Click(null, null);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
private void RecordSize()
|
||||
@@ -227,15 +223,10 @@ namespace Netch.Forms
|
||||
if (sender == null)
|
||||
throw new ArgumentNullException(nameof(sender));
|
||||
|
||||
// TODO get Util from Tag
|
||||
var s = ((ToolStripMenuItem)sender).Text;
|
||||
|
||||
var start = s.IndexOf("[", StringComparison.Ordinal) + 1;
|
||||
var end = s.IndexOf("]", start, StringComparison.Ordinal);
|
||||
var result = s.Substring(start, end - start);
|
||||
var util = (IServerUtil)((ToolStripMenuItem)sender).Tag;
|
||||
|
||||
Hide();
|
||||
ServerHelper.GetUtilByFullName(result).Create();
|
||||
util.Create();
|
||||
|
||||
LoadServers();
|
||||
Configuration.Save();
|
||||
@@ -253,6 +244,13 @@ namespace Netch.Forms
|
||||
Show();
|
||||
}
|
||||
|
||||
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Hide();
|
||||
new Route().ShowDialog();
|
||||
Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Subscription
|
||||
@@ -309,32 +307,29 @@ namespace Netch.Forms
|
||||
|
||||
#region Options
|
||||
|
||||
private void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Task.Run(() =>
|
||||
void OnNewVersionNotFound(object? o, EventArgs? args)
|
||||
{
|
||||
void OnNewVersionNotFound(object? o, EventArgs? args)
|
||||
{
|
||||
NotifyTip(i18N.Translate("Already latest version"));
|
||||
}
|
||||
NotifyTip(i18N.Translate("Already latest version"));
|
||||
}
|
||||
|
||||
void OnNewVersionFoundFailed(object? o, EventArgs? args)
|
||||
{
|
||||
NotifyTip(i18N.Translate("New version found failed"), info: false);
|
||||
}
|
||||
void OnNewVersionFoundFailed(object? o, EventArgs? args)
|
||||
{
|
||||
NotifyTip(i18N.Translate("New version found failed"), info: false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound += OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed += OnNewVersionFoundFailed;
|
||||
CheckUpdate();
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound -= OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed -= OnNewVersionFoundFailed;
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound += OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed += OnNewVersionFoundFailed;
|
||||
await CheckUpdate();
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateChecker.NewVersionNotFound -= OnNewVersionNotFound;
|
||||
UpdateChecker.NewVersionFoundFailed -= OnNewVersionFoundFailed;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
@@ -370,11 +365,10 @@ namespace Netch.Forms
|
||||
StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (NFController.UninstallDriver())
|
||||
NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
|
||||
});
|
||||
var task = Task.Run(NFController.UninstallDriver);
|
||||
|
||||
if (await task)
|
||||
NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -388,6 +382,13 @@ namespace Netch.Forms
|
||||
Firewall.RemoveNetchFwRules();
|
||||
}
|
||||
|
||||
private void ShowHideConsoleToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var windowStyles = (User32.WindowStyles)User32.GetWindowLong(Netch.ConsoleHwnd, User32.WindowLongFlags.GWL_STYLE);
|
||||
var visible = windowStyles.HasFlag(User32.WindowStyles.WS_VISIBLE);
|
||||
User32.ShowWindow(Netch.ConsoleHwnd, visible ? ShowWindowCommand.SW_HIDE : ShowWindowCommand.SW_SHOW);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -421,12 +422,9 @@ namespace Netch.Forms
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Updater.Updater.DownloadAndUpdate(Path.Combine(Global.NetchDir, "data"),
|
||||
Global.NetchDir,
|
||||
(_, args) => BeginInvoke(new Action(() => NewVersionLabel.Text = $"{args.ProgressPercentage}%")));
|
||||
});
|
||||
await Updater.DownloadAndUpdate(Path.Combine(Global.NetchDir, "data"),
|
||||
Global.NetchDir,
|
||||
(_, args) => BeginInvoke(new Action(() => NewVersionLabel.Text = $"{args.ProgressPercentage}%")));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -465,21 +463,20 @@ namespace Netch.Forms
|
||||
{
|
||||
if (!IsWaiting())
|
||||
{
|
||||
// 停止
|
||||
await StopAsyncCore();
|
||||
await StopCore();
|
||||
return;
|
||||
}
|
||||
|
||||
Configuration.Save();
|
||||
|
||||
// 服务器、模式 需选择
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
if (ServerComboBox.SelectedItem is not Server server)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(ModeComboBox.SelectedItem is Models.Mode mode))
|
||||
if (ModeComboBox.SelectedItem is not Models.Mode mode)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
|
||||
return;
|
||||
@@ -512,21 +509,17 @@ namespace Netch.Forms
|
||||
{
|
||||
while (State == State.Started)
|
||||
{
|
||||
bool StartedPingEnabled()
|
||||
{
|
||||
return Global.Settings.StartedPingInterval >= 0;
|
||||
}
|
||||
|
||||
if (StartedPingEnabled())
|
||||
if (Global.Settings.StartedPingInterval >= 0)
|
||||
{
|
||||
server.Test();
|
||||
ServerComboBox.Refresh();
|
||||
}
|
||||
|
||||
if (StartedPingEnabled())
|
||||
Thread.Sleep(Global.Settings.StartedPingInterval * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -566,11 +559,11 @@ namespace Netch.Forms
|
||||
private void LoadServers()
|
||||
{
|
||||
ServerComboBox.Items.Clear();
|
||||
ServerComboBox.Items.AddRange(Global.Settings.Server.ToArray());
|
||||
ServerComboBox.Items.AddRange(Global.Settings.Server.Cast<object>().ToArray());
|
||||
SelectLastServer();
|
||||
}
|
||||
|
||||
public void SelectLastServer()
|
||||
private void SelectLastServer()
|
||||
{
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ServerComboBoxSelectedIndex > 0 && Global.Settings.ServerComboBoxSelectedIndex < ServerComboBox.Items.Count)
|
||||
@@ -608,15 +601,20 @@ namespace Netch.Forms
|
||||
|
||||
private void SpeedPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
void Enable()
|
||||
{
|
||||
ServerComboBox.Refresh();
|
||||
Enabled = true;
|
||||
StatusText();
|
||||
}
|
||||
|
||||
Enabled = false;
|
||||
StatusText(i18N.Translate("Testing"));
|
||||
|
||||
if (!IsWaiting() || ModifierKeys == Keys.Control)
|
||||
{
|
||||
(ServerComboBox.SelectedItem as Server)?.Test();
|
||||
ServerComboBox.Refresh();
|
||||
Enabled = true;
|
||||
StatusText();
|
||||
Enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -625,11 +623,8 @@ namespace Netch.Forms
|
||||
|
||||
void OnTestDelayFinished(object? o1, EventArgs? e1)
|
||||
{
|
||||
Refresh();
|
||||
|
||||
ServerHelper.DelayTestHelper.TestDelayFinished -= OnTestDelayFinished;
|
||||
Enabled = true;
|
||||
StatusText();
|
||||
Enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -688,7 +683,7 @@ namespace Netch.Forms
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
public void SelectLastMode()
|
||||
private void SelectLastMode()
|
||||
{
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ModeComboBoxSelectedIndex > 0 && Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
|
||||
@@ -730,13 +725,13 @@ namespace Netch.Forms
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0:
|
||||
case ModeType.Process:
|
||||
Hide();
|
||||
new Process(mode).ShowDialog();
|
||||
Show();
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case ModeType.ProxyRuleIPs:
|
||||
case ModeType.BypassRuleIPs:
|
||||
Hide();
|
||||
new Route(mode).ShowDialog();
|
||||
Show();
|
||||
@@ -1005,25 +1000,19 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StopAsyncCore()
|
||||
{
|
||||
State = State.Stopping;
|
||||
await MainController.StopAsync();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
public async Task Stop()
|
||||
{
|
||||
if (IsWaiting())
|
||||
return;
|
||||
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(new Action(Stop));
|
||||
return;
|
||||
}
|
||||
await StopCore();
|
||||
}
|
||||
|
||||
StopAsyncCore().Wait();
|
||||
private async Task StopCore()
|
||||
{
|
||||
State = State.Stopping;
|
||||
await MainController.StopAsync();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
private bool IsWaiting()
|
||||
@@ -1123,28 +1112,33 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private void NatTypeStatusLabel_Click(object sender, EventArgs e)
|
||||
private async void NatTypeStatusLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_state == State.Started && NttTested)
|
||||
NatTest();
|
||||
if (_state == State.Started && !Monitor.IsEntered(_natTestLock))
|
||||
await NatTest();
|
||||
}
|
||||
|
||||
private static bool NttTested;
|
||||
private bool _natTestLock = true;
|
||||
|
||||
/// <summary>
|
||||
/// 测试 NAT
|
||||
/// </summary>
|
||||
public void NatTest()
|
||||
private async Task NatTest()
|
||||
{
|
||||
if (!MainController.Mode!.TestNatRequired())
|
||||
return;
|
||||
|
||||
NttTested = false;
|
||||
Task.Run(() =>
|
||||
{
|
||||
NatTypeStatusText(i18N.Translate("Starting NatTester"));
|
||||
if (!_natTestLock)
|
||||
return;
|
||||
|
||||
var (result, localEnd, publicEnd) = MainController.NTTController.Start().Result;
|
||||
_natTestLock = false;
|
||||
|
||||
try
|
||||
{
|
||||
NatTypeStatusText(i18N.Translate("Testing NAT"));
|
||||
|
||||
// Monitor.TryEnter() Monitor.Exit() (a.k.a. lock) not work with async/await
|
||||
var (result, _, publicEnd) = await MainController.NTTController.Start();
|
||||
|
||||
if (!string.IsNullOrEmpty(publicEnd))
|
||||
{
|
||||
@@ -1155,9 +1149,11 @@ namespace Netch.Forms
|
||||
{
|
||||
NatTypeStatusText(result ?? "Error");
|
||||
}
|
||||
|
||||
NttTested = true;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
_natTestLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1235,8 +1231,7 @@ namespace Netch.Forms
|
||||
if (File.Exists(file))
|
||||
File.Delete(file);
|
||||
|
||||
if (IsWaiting())
|
||||
await StopAsyncCore();
|
||||
await Stop();
|
||||
|
||||
Dispose();
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
@@ -1266,12 +1261,12 @@ namespace Netch.Forms
|
||||
|
||||
#region Updater
|
||||
|
||||
private void CheckUpdate()
|
||||
private async Task CheckUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
UpdateChecker.NewVersionFound += OnUpdateCheckerOnNewVersionFound;
|
||||
UpdateChecker.Check(Global.Settings.CheckBetaUpdate).Wait();
|
||||
await UpdateChecker.Check(Global.Settings.CheckBetaUpdate);
|
||||
if (Flags.AlwaysShowNewVersionFound)
|
||||
OnUpdateCheckerOnNewVersionFound(null!, null!);
|
||||
}
|
||||
@@ -1386,7 +1381,7 @@ namespace Netch.Forms
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (!(sender is ComboBox cbx))
|
||||
if (sender is not ComboBox cbx)
|
||||
return;
|
||||
|
||||
// 绘制背景颜色
|
||||
@@ -1401,38 +1396,38 @@ namespace Netch.Forms
|
||||
switch (cbx.Items[e.Index])
|
||||
{
|
||||
case Server item:
|
||||
{
|
||||
// 计算延迟底色
|
||||
var numBoxBackBrush = item.Delay switch { > 200 => Brushes.Red, > 80 => Brushes.Yellow, >= 0 => _greenBrush, _ => Brushes.Gray };
|
||||
{
|
||||
// 计算延迟底色
|
||||
var numBoxBackBrush = item.Delay switch { > 200 => Brushes.Red, > 80 => Brushes.Yellow, >= 0 => _greenBrush, _ => Brushes.Gray };
|
||||
|
||||
// 绘制延迟底色
|
||||
e.Graphics.FillRectangle(numBoxBackBrush, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
|
||||
// 绘制延迟底色
|
||||
e.Graphics.FillRectangle(numBoxBackBrush, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
|
||||
|
||||
// 绘制延迟字符串
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Delay.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
TextFormatFlags.Left);
|
||||
// 绘制延迟字符串
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Delay.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
TextFormatFlags.Left);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Models.Mode item:
|
||||
{
|
||||
// 绘制 模式Box 底色
|
||||
e.Graphics.FillRectangle(Brushes.Gray, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
|
||||
{
|
||||
// 绘制 模式Box 底色
|
||||
e.Graphics.FillRectangle(Brushes.Gray, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
|
||||
|
||||
// 绘制 模式行数 字符串
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Rule.Count.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
TextFormatFlags.Left);
|
||||
// 绘制 模式行数 字符串
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Content.Count.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
TextFormatFlags.Left);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
{
|
||||
@@ -24,7 +25,7 @@ namespace Netch.Forms.Mode
|
||||
/// <param name="mode">模式</param>
|
||||
public Process(Models.Mode? mode = null)
|
||||
{
|
||||
if (mode != null && mode.Type is not 0)
|
||||
if (mode != null && mode.Type is not ModeType.Process)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
InitializeComponent();
|
||||
@@ -62,7 +63,7 @@ namespace Netch.Forms.Mode
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
RuleAddRange(_mode.Rule);
|
||||
RuleAddRange(_mode.Content);
|
||||
}
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
@@ -116,8 +117,8 @@ namespace Netch.Forms.Mode
|
||||
if (_mode != null)
|
||||
{
|
||||
_mode.Remark = RemarkTextBox.Text;
|
||||
_mode.Rule.Clear();
|
||||
_mode.Rule.AddRange(RuleRichTextBox.Lines);
|
||||
_mode.Content.Clear();
|
||||
_mode.Content.AddRange(RuleRichTextBox.Lines);
|
||||
|
||||
_mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
@@ -134,11 +135,11 @@ namespace Netch.Forms.Mode
|
||||
|
||||
var mode = new Models.Mode(fullName)
|
||||
{
|
||||
Type = 0,
|
||||
Type = ModeType.Process,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(RuleRichTextBox.Lines);
|
||||
mode.Content.AddRange(RuleRichTextBox.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
|
||||
@@ -4,18 +4,20 @@ using Netch.Utils;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
{
|
||||
public partial class Route : Form
|
||||
{
|
||||
private readonly TagItem<int>[] _items = { new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs") };
|
||||
private readonly TagItem<ModeType>[] _items =
|
||||
{ new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") };
|
||||
|
||||
private readonly Models.Mode? _mode;
|
||||
|
||||
public Route(Models.Mode? mode = null)
|
||||
{
|
||||
if (mode != null && mode.Type is not (1 or 2))
|
||||
if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
_mode = mode;
|
||||
@@ -37,7 +39,7 @@ namespace Netch.Forms.Mode
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
richTextBox1.Lines = _mode.Rule.ToArray();
|
||||
richTextBox1.Lines = _mode.Content.ToArray();
|
||||
}
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
@@ -60,9 +62,9 @@ namespace Netch.Forms.Mode
|
||||
if (_mode != null)
|
||||
{
|
||||
_mode.Remark = RemarkTextBox.Text;
|
||||
_mode.Rule.Clear();
|
||||
_mode.Rule.AddRange(richTextBox1.Lines);
|
||||
_mode.Type = (int)comboBox1.SelectedValue;
|
||||
_mode.Content.Clear();
|
||||
_mode.Content.AddRange(richTextBox1.Lines);
|
||||
_mode.Type = (ModeType)comboBox1.SelectedValue;
|
||||
|
||||
_mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
@@ -79,11 +81,11 @@ namespace Netch.Forms.Mode
|
||||
|
||||
var mode = new Models.Mode(fullName)
|
||||
{
|
||||
Type = (int)comboBox1.SelectedValue,
|
||||
Type = (ModeType)comboBox1.SelectedValue,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(richTextBox1.Lines);
|
||||
mode.Content.AddRange(richTextBox1.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
|
||||
92
Netch/Forms/SettingForm.Designer.cs
generated
92
Netch/Forms/SettingForm.Designer.cs
generated
@@ -104,8 +104,8 @@ namespace Netch.Forms
|
||||
this.CheckBetaUpdateCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UpdateServersWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.AioDNSTabPage = new System.Windows.Forms.TabPage();
|
||||
this.AioDNSRuleRuleLabel = new System.Windows.Forms.Label();
|
||||
this.AioDNSRulePathTextBox = new System.Windows.Forms.TextBox();
|
||||
this.AioDNSListenPortLabel = new System.Windows.Forms.Label();
|
||||
this.AioDNSListenPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ChinaDNSLabel = new System.Windows.Forms.Label();
|
||||
this.ChinaDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.OtherDNSLabel = new System.Windows.Forms.Label();
|
||||
@@ -175,7 +175,7 @@ namespace Netch.Forms
|
||||
this.PortGroupBox.Controls.Add(this.AllowDevicesCheckBox);
|
||||
this.PortGroupBox.Location = new System.Drawing.Point(8, 6);
|
||||
this.PortGroupBox.Name = "PortGroupBox";
|
||||
this.PortGroupBox.Size = new System.Drawing.Size(241, 140);
|
||||
this.PortGroupBox.Size = new System.Drawing.Size(241, 115);
|
||||
this.PortGroupBox.TabIndex = 0;
|
||||
this.PortGroupBox.TabStop = false;
|
||||
this.PortGroupBox.Text = "Local Port";
|
||||
@@ -217,7 +217,7 @@ namespace Netch.Forms
|
||||
// AllowDevicesCheckBox
|
||||
//
|
||||
this.AllowDevicesCheckBox.AutoSize = true;
|
||||
this.AllowDevicesCheckBox.Location = new System.Drawing.Point(6, 107);
|
||||
this.AllowDevicesCheckBox.Location = new System.Drawing.Point(6, 84);
|
||||
this.AllowDevicesCheckBox.Name = "AllowDevicesCheckBox";
|
||||
this.AllowDevicesCheckBox.Size = new System.Drawing.Size(206, 21);
|
||||
this.AllowDevicesCheckBox.TabIndex = 6;
|
||||
@@ -240,9 +240,9 @@ namespace Netch.Forms
|
||||
this.ServerPingTypeLabel.AutoSize = true;
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 44);
|
||||
this.ServerPingTypeLabel.Name = "ServerPingTypeLabel";
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(98, 17);
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(86, 17);
|
||||
this.ServerPingTypeLabel.TabIndex = 2;
|
||||
this.ServerPingTypeLabel.Text = "ServerPingType";
|
||||
this.ServerPingTypeLabel.Text = "Ping Protocol";
|
||||
//
|
||||
// ICMPingRadioBtn
|
||||
//
|
||||
@@ -269,24 +269,24 @@ namespace Netch.Forms
|
||||
// ProfileCountLabel
|
||||
//
|
||||
this.ProfileCountLabel.AutoSize = true;
|
||||
this.ProfileCountLabel.Location = new System.Drawing.Point(12, 160);
|
||||
this.ProfileCountLabel.Location = new System.Drawing.Point(15, 140);
|
||||
this.ProfileCountLabel.Name = "ProfileCountLabel";
|
||||
this.ProfileCountLabel.Size = new System.Drawing.Size(79, 17);
|
||||
this.ProfileCountLabel.Size = new System.Drawing.Size(83, 17);
|
||||
this.ProfileCountLabel.TabIndex = 5;
|
||||
this.ProfileCountLabel.Text = "ProfileCount";
|
||||
this.ProfileCountLabel.Text = "Profile Count";
|
||||
//
|
||||
// ProfileCountTextBox
|
||||
//
|
||||
this.ProfileCountTextBox.Location = new System.Drawing.Point(120, 157);
|
||||
this.ProfileCountTextBox.Location = new System.Drawing.Point(182, 137);
|
||||
this.ProfileCountTextBox.Name = "ProfileCountTextBox";
|
||||
this.ProfileCountTextBox.Size = new System.Drawing.Size(90, 23);
|
||||
this.ProfileCountTextBox.Size = new System.Drawing.Size(70, 23);
|
||||
this.ProfileCountTextBox.TabIndex = 6;
|
||||
this.ProfileCountTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// DetectionTickLabel
|
||||
//
|
||||
this.DetectionTickLabel.AutoSize = true;
|
||||
this.DetectionTickLabel.Location = new System.Drawing.Point(225, 160);
|
||||
this.DetectionTickLabel.Location = new System.Drawing.Point(15, 170);
|
||||
this.DetectionTickLabel.Name = "DetectionTickLabel";
|
||||
this.DetectionTickLabel.Size = new System.Drawing.Size(117, 17);
|
||||
this.DetectionTickLabel.TabIndex = 7;
|
||||
@@ -294,33 +294,33 @@ namespace Netch.Forms
|
||||
//
|
||||
// DetectionTickTextBox
|
||||
//
|
||||
this.DetectionTickTextBox.Location = new System.Drawing.Point(366, 157);
|
||||
this.DetectionTickTextBox.Location = new System.Drawing.Point(182, 167);
|
||||
this.DetectionTickTextBox.Name = "DetectionTickTextBox";
|
||||
this.DetectionTickTextBox.Size = new System.Drawing.Size(68, 23);
|
||||
this.DetectionTickTextBox.Size = new System.Drawing.Size(70, 23);
|
||||
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.Location = new System.Drawing.Point(15, 200);
|
||||
this.StartedPingLabel.Name = "StartedPingLabel";
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(126, 17);
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(153, 17);
|
||||
this.StartedPingLabel.TabIndex = 9;
|
||||
this.StartedPingLabel.Text = "Delay test after start";
|
||||
this.StartedPingLabel.Text = "Delay test after start(sec)";
|
||||
//
|
||||
// StartedPingIntervalTextBox
|
||||
//
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(177, 184);
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(182, 197);
|
||||
this.StartedPingIntervalTextBox.Name = "StartedPingIntervalTextBox";
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(68, 23);
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(70, 23);
|
||||
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.Location = new System.Drawing.Point(15, 230);
|
||||
this.STUNServerLabel.Name = "STUNServerLabel";
|
||||
this.STUNServerLabel.Size = new System.Drawing.Size(82, 17);
|
||||
this.STUNServerLabel.TabIndex = 11;
|
||||
@@ -329,15 +329,15 @@ namespace Netch.Forms
|
||||
// STUN_ServerComboBox
|
||||
//
|
||||
this.STUN_ServerComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
|
||||
this.STUN_ServerComboBox.Location = new System.Drawing.Point(120, 213);
|
||||
this.STUN_ServerComboBox.Location = new System.Drawing.Point(182, 227);
|
||||
this.STUN_ServerComboBox.Name = "STUN_ServerComboBox";
|
||||
this.STUN_ServerComboBox.Size = new System.Drawing.Size(314, 25);
|
||||
this.STUN_ServerComboBox.Size = new System.Drawing.Size(264, 25);
|
||||
this.STUN_ServerComboBox.TabIndex = 12;
|
||||
//
|
||||
// LanguageLabel
|
||||
//
|
||||
this.LanguageLabel.AutoSize = true;
|
||||
this.LanguageLabel.Location = new System.Drawing.Point(12, 254);
|
||||
this.LanguageLabel.Location = new System.Drawing.Point(15, 260);
|
||||
this.LanguageLabel.Name = "LanguageLabel";
|
||||
this.LanguageLabel.Size = new System.Drawing.Size(65, 17);
|
||||
this.LanguageLabel.TabIndex = 15;
|
||||
@@ -347,9 +347,9 @@ namespace Netch.Forms
|
||||
//
|
||||
this.LanguageComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.LanguageComboBox.FormattingEnabled = true;
|
||||
this.LanguageComboBox.Location = new System.Drawing.Point(120, 251);
|
||||
this.LanguageComboBox.Location = new System.Drawing.Point(182, 257);
|
||||
this.LanguageComboBox.Name = "LanguageComboBox";
|
||||
this.LanguageComboBox.Size = new System.Drawing.Size(121, 25);
|
||||
this.LanguageComboBox.Size = new System.Drawing.Size(110, 25);
|
||||
this.LanguageComboBox.TabIndex = 16;
|
||||
//
|
||||
// NFTabPage
|
||||
@@ -872,8 +872,8 @@ namespace Netch.Forms
|
||||
//
|
||||
// AioDNSTabPage
|
||||
//
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSRuleRuleLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSRulePathTextBox);
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSListenPortLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSListenPortTextBox);
|
||||
this.AioDNSTabPage.Controls.Add(this.ChinaDNSLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.ChinaDNSTextBox);
|
||||
this.AioDNSTabPage.Controls.Add(this.OtherDNSLabel);
|
||||
@@ -886,27 +886,27 @@ namespace Netch.Forms
|
||||
this.AioDNSTabPage.Text = "AioDNS";
|
||||
this.AioDNSTabPage.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// AioDNSRuleRuleLabel
|
||||
// AioDNSListenPortLabel
|
||||
//
|
||||
this.AioDNSRuleRuleLabel.AutoSize = true;
|
||||
this.AioDNSRuleRuleLabel.Location = new System.Drawing.Point(16, 30);
|
||||
this.AioDNSRuleRuleLabel.Name = "AioDNSRuleRuleLabel";
|
||||
this.AioDNSRuleRuleLabel.Size = new System.Drawing.Size(56, 17);
|
||||
this.AioDNSRuleRuleLabel.TabIndex = 0;
|
||||
this.AioDNSRuleRuleLabel.Text = "Rule File";
|
||||
this.AioDNSListenPortLabel.AutoSize = true;
|
||||
this.AioDNSListenPortLabel.Location = new System.Drawing.Point(15, 103);
|
||||
this.AioDNSListenPortLabel.Name = "AioDNSListenPortLabel";
|
||||
this.AioDNSListenPortLabel.Size = new System.Drawing.Size(69, 17);
|
||||
this.AioDNSListenPortLabel.TabIndex = 0;
|
||||
this.AioDNSListenPortLabel.Text = "Listen Port";
|
||||
//
|
||||
// AioDNSRulePathTextBox
|
||||
// AioDNSListenPortTextBox
|
||||
//
|
||||
this.AioDNSRulePathTextBox.Enabled = false;
|
||||
this.AioDNSRulePathTextBox.Location = new System.Drawing.Point(150, 30);
|
||||
this.AioDNSRulePathTextBox.Name = "AioDNSRulePathTextBox";
|
||||
this.AioDNSRulePathTextBox.Size = new System.Drawing.Size(201, 23);
|
||||
this.AioDNSRulePathTextBox.TabIndex = 1;
|
||||
this.AioDNSListenPortTextBox.Location = new System.Drawing.Point(150, 100);
|
||||
this.AioDNSListenPortTextBox.Name = "AioDNSListenPortTextBox";
|
||||
this.AioDNSListenPortTextBox.Size = new System.Drawing.Size(80, 23);
|
||||
this.AioDNSListenPortTextBox.TabIndex = 1;
|
||||
this.AioDNSListenPortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// ChinaDNSLabel
|
||||
//
|
||||
this.ChinaDNSLabel.AutoSize = true;
|
||||
this.ChinaDNSLabel.Location = new System.Drawing.Point(16, 70);
|
||||
this.ChinaDNSLabel.Location = new System.Drawing.Point(15, 23);
|
||||
this.ChinaDNSLabel.Name = "ChinaDNSLabel";
|
||||
this.ChinaDNSLabel.Size = new System.Drawing.Size(70, 17);
|
||||
this.ChinaDNSLabel.TabIndex = 2;
|
||||
@@ -914,7 +914,7 @@ namespace Netch.Forms
|
||||
//
|
||||
// ChinaDNSTextBox
|
||||
//
|
||||
this.ChinaDNSTextBox.Location = new System.Drawing.Point(150, 70);
|
||||
this.ChinaDNSTextBox.Location = new System.Drawing.Point(150, 20);
|
||||
this.ChinaDNSTextBox.Name = "ChinaDNSTextBox";
|
||||
this.ChinaDNSTextBox.Size = new System.Drawing.Size(201, 23);
|
||||
this.ChinaDNSTextBox.TabIndex = 3;
|
||||
@@ -923,7 +923,7 @@ namespace Netch.Forms
|
||||
// OtherDNSLabel
|
||||
//
|
||||
this.OtherDNSLabel.AutoSize = true;
|
||||
this.OtherDNSLabel.Location = new System.Drawing.Point(16, 110);
|
||||
this.OtherDNSLabel.Location = new System.Drawing.Point(15, 63);
|
||||
this.OtherDNSLabel.Name = "OtherDNSLabel";
|
||||
this.OtherDNSLabel.Size = new System.Drawing.Size(71, 17);
|
||||
this.OtherDNSLabel.TabIndex = 4;
|
||||
@@ -931,7 +931,7 @@ namespace Netch.Forms
|
||||
//
|
||||
// OtherDNSTextBox
|
||||
//
|
||||
this.OtherDNSTextBox.Location = new System.Drawing.Point(150, 110);
|
||||
this.OtherDNSTextBox.Location = new System.Drawing.Point(150, 60);
|
||||
this.OtherDNSTextBox.Name = "OtherDNSTextBox";
|
||||
this.OtherDNSTextBox.Size = new System.Drawing.Size(201, 23);
|
||||
this.OtherDNSTextBox.TabIndex = 5;
|
||||
@@ -1067,8 +1067,8 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.TextBox ttiTextBox;
|
||||
private System.Windows.Forms.CheckBox UseMuxCheckBox;
|
||||
private System.Windows.Forms.TabPage AioDNSTabPage;
|
||||
private System.Windows.Forms.Label AioDNSRuleRuleLabel;
|
||||
private System.Windows.Forms.TextBox AioDNSRulePathTextBox;
|
||||
private System.Windows.Forms.Label AioDNSListenPortLabel;
|
||||
private System.Windows.Forms.TextBox AioDNSListenPortTextBox;
|
||||
private System.Windows.Forms.Label OtherDNSLabel;
|
||||
private System.Windows.Forms.Label ChinaDNSLabel;
|
||||
private System.Windows.Forms.TextBox OtherDNSTextBox;
|
||||
|
||||
@@ -211,12 +211,15 @@ namespace Netch.Forms
|
||||
|
||||
#region AioDNS
|
||||
|
||||
BindTextBox(AioDNSRulePathTextBox, _ => true, s => Global.Settings.AioDNS.RulePath = s, Global.Settings.AioDNS.RulePath);
|
||||
|
||||
BindTextBox(ChinaDNSTextBox, _ => true, s => Global.Settings.AioDNS.ChinaDNS = s, Global.Settings.AioDNS.ChinaDNS);
|
||||
|
||||
BindTextBox(OtherDNSTextBox, _ => true, s => Global.Settings.AioDNS.OtherDNS = s, Global.Settings.AioDNS.OtherDNS);
|
||||
|
||||
BindTextBox(AioDNSListenPortTextBox,
|
||||
s => ushort.TryParse(s, out _),
|
||||
s => Global.Settings.AioDNS.ListenPort = ushort.Parse(s),
|
||||
Global.Settings.AioDNS.ListenPort);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IController
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IModeController : IController
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IServerController : IController
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
using Netch.Controllers;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Models
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IServerUtil
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
string[] UriScheme { get; }
|
||||
|
||||
public abstract Type ServerType { get; }
|
||||
public Type ServerType { get; }
|
||||
|
||||
public void Edit(Server s);
|
||||
|
||||
@@ -36,9 +36,9 @@ namespace Netch.Models
|
||||
|
||||
string GetShareLink(Server s);
|
||||
|
||||
public abstract IServerController GetController();
|
||||
public IServerController GetController();
|
||||
|
||||
public abstract IEnumerable<Server> ParseUri(string text);
|
||||
public IEnumerable<Server> ParseUri(string text);
|
||||
|
||||
bool CheckServer(Server s);
|
||||
}
|
||||
@@ -3,12 +3,13 @@ using System.Text;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class AioDNSInterops
|
||||
public static class AioDNS
|
||||
{
|
||||
private const string aiodns_bin = "aiodns.bin";
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Global.Logger.Debug($"[aiodns] Dial {name}: {value}");
|
||||
return aiodns_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class RedirectorInterop
|
||||
public static class Redirector
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace Netch.Interops
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Global.Logger.Debug($"Dial {name} {value}");
|
||||
Global.Logger.Debug($"[Redirector] Dial {name}: {value}");
|
||||
return aio_dial(name, value);
|
||||
}
|
||||
|
||||
26
Netch/Interops/RouteHelper.cs
Normal file
26
Netch/Interops/RouteHelper.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class RouteHelper
|
||||
{
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong ConvertLuidToIndex(ulong id);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateIPv4(string address, string netmask, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool RefreshIPTable(AddressFamily inet, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool DeleteRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class TUNInterop
|
||||
public static class tun2socks
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
@@ -35,12 +35,13 @@ namespace Netch.Interops
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Global.Logger.Debug($"Dial {name} {value}");
|
||||
Global.Logger.Debug($"[tun2socks] Dial {name}: {value}");
|
||||
return tun_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
{
|
||||
Global.Logger.Debug($"[tun2socks] init");
|
||||
return tun_init();
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Netch.Models.GitHubRelease
|
||||
if (versionComparison != 0)
|
||||
return versionComparison;
|
||||
|
||||
var suffixExistComparison = (Suffix != null ? 1 : 0) - (other.Suffix != null ? 1 : 0);
|
||||
var suffixExistComparison = (Suffix == null ? 1 : 0) - (other.Suffix == null ? 1 : 0);
|
||||
if (suffixExistComparison != 0)
|
||||
return suffixExistComparison;
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public interface IAdapter
|
||||
{
|
||||
ulong InterfaceIndex { get; }
|
||||
|
||||
IPAddress Gateway { get; }
|
||||
|
||||
NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,138 +4,126 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class Mode
|
||||
{
|
||||
private readonly Lazy<List<string>> _lazyRule;
|
||||
|
||||
public string? FullName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fullName">Mode File FullPath</param>
|
||||
/// <exception cref="FormatException"></exception>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public Mode(string? fullName)
|
||||
{
|
||||
_lazyRule = new Lazy<List<string>>(ReadRules);
|
||||
if (fullName == null)
|
||||
return;
|
||||
|
||||
FullName = fullName;
|
||||
if (!File.Exists(FullName))
|
||||
if (FullName == null || !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;
|
||||
if (!ModeHelper.ModeTypes.Contains(Type))
|
||||
throw new NotSupportedException($"not support mode \"[{Type}]{Remark}\".");
|
||||
(Remark, Type) = ReadHead(FullName);
|
||||
}
|
||||
|
||||
public string? FullName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 规则
|
||||
/// </summary>
|
||||
public List<string> Rule => _lazyRule.Value;
|
||||
public List<string> Content => _content ??= ReadContent();
|
||||
|
||||
private List<string>? _content;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// <para />
|
||||
/// 0. Socks5 + 进程加速
|
||||
/// <para />
|
||||
/// 1. Socks5 + TUN/TAP 规则内 IP CIDR 加速
|
||||
/// <para />
|
||||
/// 2. Socks5 + TUN/TAP 全局,绕过规则内 IP CIDR
|
||||
/// <para />
|
||||
/// 3. Socks5 + HTTP 代理(设置到系统代理)
|
||||
/// <para />
|
||||
/// 4. Socks5 代理(不设置到系统代理)
|
||||
/// <para />
|
||||
/// 5. Socks5 + HTTP 代理(不设置到系统代理)
|
||||
/// <para />
|
||||
/// </summary>
|
||||
public int Type { get; set; } = 0;
|
||||
public ModeType Type { get; set; } = ModeType.Process;
|
||||
|
||||
/// <summary>
|
||||
/// 文件相对路径(必须是存在的文件)
|
||||
/// </summary>
|
||||
public string? RelativePath => FullName == null ? null : ModeHelper.GetRelativePath(FullName);
|
||||
|
||||
public List<string> FullRule
|
||||
public IEnumerable<string> GetRules()
|
||||
{
|
||||
get
|
||||
var result = new List<string>();
|
||||
foreach (var s in Content)
|
||||
{
|
||||
var result = new List<string>();
|
||||
foreach (var s in Rule)
|
||||
if (string.IsNullOrWhiteSpace(s))
|
||||
continue;
|
||||
|
||||
if (s.StartsWith("//"))
|
||||
continue;
|
||||
|
||||
const string include = "#include";
|
||||
if (s.StartsWith(include))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(s))
|
||||
continue;
|
||||
var relativePath = new StringBuilder(s[include.Length..].Trim());
|
||||
relativePath.Replace("<", "").Replace(">", "");
|
||||
relativePath.Replace(".h", ".txt");
|
||||
|
||||
if (s.StartsWith("//"))
|
||||
continue;
|
||||
var mode = Global.Modes.FirstOrDefault(m => m.RelativePath?.Equals(relativePath.ToString()) ?? false) ??
|
||||
throw new MessageException($"{relativePath} file included in {Remark} not found");
|
||||
|
||||
if (s.StartsWith("#include"))
|
||||
{
|
||||
var relativePath = new StringBuilder(s.Substring(8).Trim());
|
||||
relativePath.Replace("<", "");
|
||||
relativePath.Replace(">", "");
|
||||
relativePath.Replace(".h", ".txt");
|
||||
if (mode == this)
|
||||
throw new MessageException("Can't self-reference");
|
||||
|
||||
var mode = Global.Modes.FirstOrDefault(m => m.FullName != null && m.RelativePath!.Equals(relativePath.ToString()));
|
||||
if (mode.Type != Type)
|
||||
throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
|
||||
|
||||
if (mode == null)
|
||||
throw new MessageException($"{relativePath} file included in {Remark} not found");
|
||||
if (mode.Content.Any(rule => rule.StartsWith(include)))
|
||||
throw new Exception("Cannot reference mode that reference other mode");
|
||||
|
||||
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
|
||||
{
|
||||
result.Add(s);
|
||||
}
|
||||
result.AddRange(mode.GetRules());
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(s);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<string> ReadRules()
|
||||
private static (string, ModeType) ReadHead(string fileName)
|
||||
{
|
||||
var text = File.ReadLines(fileName).First();
|
||||
if (text.First() != '#')
|
||||
throw new FormatException($"{fileName} head not found at Line 0");
|
||||
|
||||
var split = text[1..].SplitTrimEntries(',');
|
||||
|
||||
var typeNumber = int.TryParse(split.ElementAtOrDefault(1), out var type) ? type : 0;
|
||||
if (!Enum.GetValues(typeof(ModeType)).Cast<int>().Contains(typeNumber))
|
||||
throw new NotSupportedException($"Not support mode \"{typeNumber}\".");
|
||||
|
||||
return (split[0], (ModeType)typeNumber);
|
||||
}
|
||||
|
||||
private List<string> ReadContent()
|
||||
{
|
||||
if (FullName == null || !File.Exists(FullName))
|
||||
return new List<string>();
|
||||
|
||||
return File.ReadLines(FullName!).Skip(1).ToList();
|
||||
return File.ReadLines(FullName).Skip(1).ToList();
|
||||
}
|
||||
|
||||
public void WriteFile(string? fullName = null)
|
||||
public void ResetContent()
|
||||
{
|
||||
if (fullName != null)
|
||||
throw new NotImplementedException();
|
||||
_content = null;
|
||||
}
|
||||
|
||||
public void WriteFile()
|
||||
{
|
||||
var dir = Path.GetDirectoryName(FullName)!;
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
var content = $"# {Remark}, {(int)Type}{Constants.EOF}{string.Join(Constants.EOF, Content)}";
|
||||
// 写入到模式文件里
|
||||
File.WriteAllText(FullName!, ToFileString());
|
||||
File.WriteAllText(FullName!, content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,16 +132,7 @@ namespace Netch.Models
|
||||
/// <returns>备注</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{Type + 1}] {i18N.Translate(Remark)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模式文件字符串
|
||||
/// </summary>
|
||||
/// <returns>模式文件字符串</returns>
|
||||
public string ToFileString()
|
||||
{
|
||||
return $"# {Remark}, {Type}{Constants.EOF}{string.Join(Constants.EOF, Rule)}";
|
||||
return $"[{(int)Type + 1}] {i18N.Translate(Remark)}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +141,7 @@ namespace Netch.Models
|
||||
/// 是否会转发 UDP
|
||||
public static bool TestNatRequired(this Mode mode)
|
||||
{
|
||||
return mode.Type is 0 or 2;
|
||||
return mode.Type is ModeType.Process or ModeType.BypassRuleIPs;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Netch/Models/NetRoute.cs
Normal file
50
Netch/Models/NetRoute.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public struct NetRoute
|
||||
{
|
||||
public static NetRoute TemplateBuilder(string gateway, int interfaceIndex, int metric = 0)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Gateway = gateway,
|
||||
InterfaceIndex = interfaceIndex,
|
||||
Metric = metric
|
||||
};
|
||||
}
|
||||
|
||||
public static (NetRoute, IPAddress address) GetBestRouteTemplate()
|
||||
{
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var route) != 0)
|
||||
throw new MessageException("GetBestRoute 搜索失败");
|
||||
|
||||
var address = new IPAddress(route.dwForwardNextHop.S_addr);
|
||||
var gateway = new IPAddress(route.dwForwardNextHop.S_un_b);
|
||||
return (TemplateBuilder(gateway.ToString(), (int)route.dwForwardIfIndex), address);
|
||||
}
|
||||
|
||||
public int InterfaceIndex;
|
||||
|
||||
public string Gateway;
|
||||
|
||||
public string Network;
|
||||
|
||||
public byte Cidr;
|
||||
|
||||
public int Metric;
|
||||
|
||||
public NetRoute FillTemplate(string network, byte cidr, int? metric = null)
|
||||
{
|
||||
var o = (NetRoute)MemberwiseClone();
|
||||
o.Network = network;
|
||||
o.Cidr = cidr;
|
||||
if (metric != null)
|
||||
o.Metric = (int)metric;
|
||||
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public readonly struct Range
|
||||
public readonly struct NumberRange
|
||||
{
|
||||
public int Start { get; }
|
||||
|
||||
public int End { get; }
|
||||
|
||||
public Range(int start, int end)
|
||||
public NumberRange(int start, int end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class OutboundAdapter : IAdapter
|
||||
{
|
||||
public OutboundAdapter()
|
||||
{
|
||||
// 寻找出口适配器
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0)
|
||||
{
|
||||
throw new MessageException("GetBestRoute 搜索失败");
|
||||
}
|
||||
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.First(ni => ni.Supports(NetworkInterfaceComponent.IPv4) &&
|
||||
ni.GetIPProperties().GetIPv4Properties().Index == pRoute.dwForwardIfIndex);
|
||||
|
||||
Address = new IPAddress(pRoute.dwForwardNextHop.S_addr);
|
||||
InterfaceIndex = (ulong)pRoute.dwForwardIfIndex;
|
||||
Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
|
||||
|
||||
Global.Logger.Info($"出口 网关 地址:{Gateway}");
|
||||
Global.Logger.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
|
||||
}
|
||||
|
||||
public IPAddress Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public ulong InterfaceIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -80,9 +80,7 @@ namespace Netch.Models
|
||||
|
||||
public string OtherDNS { get; set; } = "tcp://1.1.1.1:53";
|
||||
|
||||
public ushort ListenPort { get; set; } = 53;
|
||||
|
||||
public string RulePath { get; set; } = "bin\\aiodns.conf";
|
||||
public ushort ListenPort { get; set; } = 253;
|
||||
}
|
||||
|
||||
public class RedirectorConfig
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
using Netch.Interops;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class TunAdapter : IAdapter
|
||||
{
|
||||
public TunAdapter()
|
||||
{
|
||||
InterfaceIndex = NativeMethods.ConvertLuidToIndex(TUNInterop.tun_luid());
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.GetIPProperties().GetIPv4Properties().Index == (int)InterfaceIndex);
|
||||
Gateway = IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
|
||||
|
||||
Global.Logger.Info($"WinTUN 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
|
||||
}
|
||||
|
||||
|
||||
public ulong InterfaceIndex { get; }
|
||||
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -7,23 +6,5 @@ namespace Netch
|
||||
{
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint RefreshDNSCache();
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong ConvertLuidToIndex(ulong id);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateIPv4(string address, string netmask, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool RefreshIPTable(AddressFamily inet, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool DeleteRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using Netch.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -8,6 +9,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Vanara.PInvoke;
|
||||
using static Vanara.PInvoke.Kernel32;
|
||||
|
||||
namespace Netch
|
||||
@@ -16,17 +18,17 @@ namespace Netch
|
||||
{
|
||||
public static readonly SingleInstance.SingleInstance SingleInstance = new($"Global\\{nameof(Netch)}");
|
||||
|
||||
public static HWND ConsoleHwnd { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
#if DEBUG
|
||||
AttachAllocConsole();
|
||||
#else
|
||||
if (args.Contains(Constants.Parameter.Console))
|
||||
AttachAllocConsole();
|
||||
ConsoleHwnd = GetConsoleWindow();
|
||||
#if RELEASE
|
||||
User32.ShowWindow(ConsoleHwnd, ShowWindowCommand.SW_HIDE);
|
||||
#endif
|
||||
|
||||
if (args.Contains(Constants.Parameter.ForceUpdate))
|
||||
@@ -38,7 +40,7 @@ namespace Netch
|
||||
Environment.SetEnvironmentVariable("PATH", $"{Environment.GetEnvironmentVariable("PATH")};{binPath}");
|
||||
AddDllDirectory(binPath);
|
||||
|
||||
Updater.Updater.CleanOld(Global.NetchDir);
|
||||
Updater.CleanOld(Global.NetchDir);
|
||||
|
||||
// 预创建目录
|
||||
var directories = new[] { "mode\\Custom", "data", "i18n", "logging" };
|
||||
@@ -93,12 +95,6 @@ namespace Netch
|
||||
Application.Run(Global.MainForm);
|
||||
}
|
||||
|
||||
private static void AttachAllocConsole()
|
||||
{
|
||||
if (!AttachConsole(ATTACH_PARENT_PROCESS))
|
||||
AllocConsole();
|
||||
}
|
||||
|
||||
public static void Application_OnException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
Global.Logger.Error(e.Exception.ToString());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<OutputType>Exe</OutputType>
|
||||
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
@@ -38,16 +39,17 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HMBSbige.SingleInstance" Version="5.0.0" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.69" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.2.4089">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
<PackageReference Include="System.Management" Version="5.0.0" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.9.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.7" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.9" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.7" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.9" />
|
||||
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
|
||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
"Stopping": "正在停止中",
|
||||
"Stopped": "已停止",
|
||||
"Starting {0}": "正在启动 {0}",
|
||||
"Starting NatTester": "正在启动 NAT 测试",
|
||||
"SetupBypass": "设置绕行规则",
|
||||
"Testing NAT": "正在测试 NAT",
|
||||
"Setup Route Table Rule": "配置路由规则",
|
||||
"Test failed": "测试失败",
|
||||
"Starting update subscription": "正在更新订阅",
|
||||
"Subscription updated": "订阅更新完毕",
|
||||
@@ -87,6 +87,7 @@
|
||||
"Remove Netch Firewall Rules": "移除 Netch 防火墙规则",
|
||||
|
||||
"Open Directory": "打开目录",
|
||||
"Show/Hide Console": "显示/隐藏控制台",
|
||||
|
||||
"About": "关于",
|
||||
"FAQ": "常见问题",
|
||||
@@ -151,9 +152,9 @@
|
||||
"Handle process's DNS Hijack": "被代理进程 DNS 劫持",
|
||||
"Global ICMP Hijack": "全局 ICMP 劫持",
|
||||
"Child Process Handle": "子进程代理",
|
||||
"ProfileCount": "快捷配置数量",
|
||||
"Delay test after start": "启动后延迟测试",
|
||||
"ServerPingType": "测速方式",
|
||||
"Profile Count": "快捷配置数量",
|
||||
"Delay test after start(sec)": "启动后延迟测试(秒)",
|
||||
"Ping Protocol": "延迟测试协议",
|
||||
"Detection Tick(sec)": "检测心跳(秒)",
|
||||
"STUN Server": "STUN 服务器",
|
||||
"Language": "语言",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks.Form;
|
||||
using Netch.Servers.Shadowsocks.Models.SSD;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks.Form;
|
||||
using Netch.Servers.Shadowsocks.Models.SSD;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Netch.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.ShadowsocksR.Form;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5.Form;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5.Form;
|
||||
|
||||
namespace Netch.Servers.Socks5
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Models;
|
||||
|
||||
namespace Netch.Servers.Trojan
|
||||
{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Form;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Form;
|
||||
|
||||
namespace Netch.Servers.Trojan
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Netch.Servers.V2ray.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Netch.Enums;
|
||||
using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig;
|
||||
|
||||
namespace Netch.Servers.V2ray.Utils
|
||||
@@ -65,7 +66,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
outboundTag = "block"
|
||||
};
|
||||
|
||||
if (mode.Type is 0 or 1 or 2)
|
||||
if (mode.Type is ModeType.Process or ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs)
|
||||
blockRuleObject.ip.Add("geoip:private");
|
||||
|
||||
static bool CheckRuleItem(ref RulesItem rulesItem)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray.Utils;
|
||||
|
||||
namespace Netch.Servers.V2ray
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
|
||||
namespace Netch.Servers.VLESS
|
||||
{
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
using Netch.Servers.VMess.Form;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
using Netch.Servers.VMess.Form;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.VMess
|
||||
{
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
@@ -10,8 +6,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Updater
|
||||
namespace Netch.Services
|
||||
{
|
||||
public class Updater
|
||||
{
|
||||
@@ -25,7 +26,7 @@ namespace Netch.Updater
|
||||
/// <param name="onDownloadProgressChanged"></param>
|
||||
/// <param name="keyword"></param>
|
||||
/// <exception cref="MessageException"></exception>
|
||||
public static void DownloadAndUpdate(string downloadDirectory,
|
||||
public static async Task DownloadAndUpdate(string downloadDirectory,
|
||||
string installDirectory,
|
||||
DownloadProgressChangedEventHandler onDownloadProgressChanged,
|
||||
string? keyword = null)
|
||||
@@ -40,7 +41,7 @@ namespace Netch.Updater
|
||||
{
|
||||
if (Utils.Utils.SHA256CheckSum(updateFile) == sha256)
|
||||
{
|
||||
updater.ApplyUpdate();
|
||||
await updater.ApplyUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ namespace Netch.Updater
|
||||
}
|
||||
|
||||
DownloadUpdateFile(onDownloadProgressChanged, updateFile, sha256);
|
||||
updater.ApplyUpdate();
|
||||
await updater.ApplyUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +95,7 @@ namespace Netch.Updater
|
||||
|
||||
private static readonly ImmutableArray<string> KeepDirectories = new List<string> { "data", "mode\\Custom", "logging" }.ToImmutableArray();
|
||||
|
||||
private void ApplyUpdate()
|
||||
private async Task ApplyUpdate()
|
||||
{
|
||||
var mainForm = Global.MainForm;
|
||||
|
||||
@@ -102,7 +103,7 @@ namespace Netch.Updater
|
||||
|
||||
ModeHelper.SuspendWatcher = true;
|
||||
// Stop and Save
|
||||
mainForm.Stop();
|
||||
await mainForm.Stop();
|
||||
Configuration.Save();
|
||||
|
||||
// Backup Configuration file
|
||||
@@ -75,7 +75,8 @@ namespace Netch.Utils
|
||||
if (!Directory.Exists(DataDirectoryFullName))
|
||||
Directory.CreateDirectory(DataDirectoryFullName);
|
||||
|
||||
File.WriteAllBytes(SettingFileFullName, JsonSerializer.SerializeToUtf8Bytes(Global.Settings, JsonSerializerOptions));
|
||||
using var fileStream = File.Create(SettingFileFullName);
|
||||
JsonSerializer.SerializeAsync(fileStream, Global.Settings, JsonSerializerOptions).Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,7 @@ namespace Netch.Utils
|
||||
/// </summary>
|
||||
private static readonly Hashtable Cache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 查询
|
||||
/// </summary>
|
||||
/// <param name="hostname">主机名</param>
|
||||
/// <returns></returns>
|
||||
public static IPAddress? Lookup(string hostname)
|
||||
public static IPAddress? Lookup(string hostname, int timeout = 3000)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -26,7 +21,7 @@ namespace Netch.Utils
|
||||
return Cache[hostname] as IPAddress;
|
||||
|
||||
var task = Dns.GetHostAddressesAsync(hostname);
|
||||
if (!task.Wait(1000))
|
||||
if (!task.Wait(timeout))
|
||||
return null;
|
||||
|
||||
if (task.Result.Length == 0)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Netch.Controllers;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -111,35 +113,33 @@ namespace Netch.Utils
|
||||
{
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0:
|
||||
case ModeType.Process:
|
||||
return server switch
|
||||
{
|
||||
Socks5 => true,
|
||||
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS => true,
|
||||
_ => false
|
||||
};
|
||||
case 1:
|
||||
case 2:
|
||||
case ModeType.ProxyRuleIPs:
|
||||
case ModeType.BypassRuleIPs:
|
||||
return server is Socks5;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly int[] ModeTypes = { 0, 1, 2, 6 };
|
||||
|
||||
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName)
|
||||
public static IModeController GetModeControllerByType(ModeType type, out ushort? port, out string portName)
|
||||
{
|
||||
port = null;
|
||||
portName = string.Empty;
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
case ModeType.Process:
|
||||
return new NFController();
|
||||
case 1:
|
||||
case 2:
|
||||
case ModeType.ProxyRuleIPs:
|
||||
case ModeType.BypassRuleIPs:
|
||||
return new TUNController();
|
||||
case 6:
|
||||
case ModeType.Pcap2Socks:
|
||||
return new PcapController();
|
||||
default:
|
||||
Global.Logger.Error("未知模式类型");
|
||||
|
||||
96
Netch/Utils/NetworkInterfaceUtils.cs
Normal file
96
Netch/Utils/NetworkInterfaceUtils.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using Netch.Models;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class NetworkInterfaceUtils
|
||||
{
|
||||
public static NetworkInterface GetBest(AddressFamily addressFamily = AddressFamily.InterNetwork)
|
||||
{
|
||||
var ipAddress = addressFamily switch
|
||||
{
|
||||
AddressFamily.InterNetwork => "114.114.114.114",
|
||||
AddressFamily.InterNetworkV6 => throw new NotImplementedException(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(addressFamily), addressFamily, null)
|
||||
};
|
||||
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0), 0, out var route) != 0)
|
||||
throw new MessageException("GetBestRoute 搜索失败");
|
||||
|
||||
return Get((int)route.dwForwardIfIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="interfaceIndex"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <returns></returns>
|
||||
public static NetworkInterface Get(int interfaceIndex)
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces().First(n => n.GetIndex() == interfaceIndex);
|
||||
}
|
||||
|
||||
public static NetworkInterface Get(string description)
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces().First(n => n.Description == description);
|
||||
}
|
||||
|
||||
public static void SetInterfaceMetric(int interfaceIndex, int? metric = null)
|
||||
{
|
||||
var arguments = $"interface ip set interface {interfaceIndex} ";
|
||||
if (metric != null)
|
||||
arguments += $"metric={metric} ";
|
||||
|
||||
Utils.ProcessRunHiddenAsync("netsh", arguments).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
public static class NetworkInterfaceExtension
|
||||
{
|
||||
public static int GetIndex(this NetworkInterface ni)
|
||||
{
|
||||
var ipProperties = ni.GetIPProperties();
|
||||
if (ni.Supports(NetworkInterfaceComponent.IPv4))
|
||||
return ipProperties.GetIPv4Properties().Index;
|
||||
|
||||
if (ni.Supports(NetworkInterfaceComponent.IPv6))
|
||||
return ipProperties.GetIPv6Properties().Index;
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void SetDns(this NetworkInterface ni, string primaryDns, string? secondDns = null)
|
||||
{
|
||||
void VerifyDns(ref string s)
|
||||
{
|
||||
s = s.Trim();
|
||||
if (primaryDns.IsNullOrEmpty())
|
||||
throw new ArgumentException("DNS format invalid", nameof(primaryDns));
|
||||
}
|
||||
|
||||
VerifyDns(ref primaryDns);
|
||||
if (secondDns != null)
|
||||
VerifyDns(ref primaryDns);
|
||||
|
||||
var wmi = new ManagementClass("Win32_NetworkAdapterConfiguration");
|
||||
var mos = wmi.GetInstances().Cast<ManagementObject>();
|
||||
|
||||
var mo = mos.First(m => m["Description"].ToString() == ni.Description);
|
||||
|
||||
var dns = new[] { primaryDns };
|
||||
if (secondDns != null)
|
||||
dns = dns.Append(secondDns).ToArray();
|
||||
|
||||
var inPar = mo.GetMethodParameters("SetDNSServerSearchOrder");
|
||||
inPar["DNSServerSearchOrder"] = dns;
|
||||
|
||||
mo.InvokeMethod("SetDNSServerSearchOrder", inPar, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,16 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Models;
|
||||
using static Vanara.PInvoke.IpHlpApi;
|
||||
using static Vanara.PInvoke.Ws2_32;
|
||||
using Range = Netch.Models.Range;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class PortHelper
|
||||
{
|
||||
private static readonly List<Range> TCPReservedRanges = new();
|
||||
private static readonly List<Range> UDPReservedRanges = new();
|
||||
private static readonly List<NumberRange> TCPReservedRanges = new();
|
||||
private static readonly List<NumberRange> UDPReservedRanges = new();
|
||||
private static readonly IPGlobalProperties NetInfo = IPGlobalProperties.GetIPGlobalProperties();
|
||||
|
||||
static PortHelper()
|
||||
@@ -38,7 +38,7 @@ namespace Netch.Utils
|
||||
return row.Select(r => Process.GetProcessById((int)r.dwOwningPid));
|
||||
}
|
||||
|
||||
private static void GetReservedPortRange(PortType portType, ref List<Range> targetList)
|
||||
private static void GetReservedPortRange(PortType portType, ref List<NumberRange> targetList)
|
||||
{
|
||||
var process = new Process
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace Netch.Utils
|
||||
if (!ushort.TryParse(value[0], out var start) || !ushort.TryParse(value[1], out var end))
|
||||
continue;
|
||||
|
||||
targetList.Add(new Range(start, end));
|
||||
targetList.Add(new NumberRange(start, end));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
69
Netch/Utils/RouteUtils.cs
Normal file
69
Netch/Utils/RouteUtils.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Sockets;
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class RouteUtils
|
||||
{
|
||||
public static void CreateRouteFill(NetRoute template, IEnumerable<string> rules, int? metric = null)
|
||||
{
|
||||
foreach (var rule in rules)
|
||||
CreateRouteFill(template, rule, metric);
|
||||
}
|
||||
|
||||
public static bool CreateRouteFill(NetRoute template, string rule, int? metric = null)
|
||||
{
|
||||
if (!TryParseIPNetwork(rule, out var network, out var cidr))
|
||||
{
|
||||
Global.Logger.Warning($"invalid rule {rule}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return CreateRoute(template.FillTemplate(network, (byte)cidr, metric));
|
||||
}
|
||||
|
||||
public static bool CreateRoute(NetRoute o)
|
||||
{
|
||||
return RouteHelper.CreateRoute(AddressFamily.InterNetwork, o.Network, o.Cidr, o.Gateway, (ulong)o.InterfaceIndex, o.Metric);
|
||||
}
|
||||
|
||||
public static void DeleteRouteFill(NetRoute template, IEnumerable<string> rules, int? metric = null)
|
||||
{
|
||||
foreach (var rule in rules)
|
||||
DeleteRouteFill(template, rule, metric);
|
||||
}
|
||||
|
||||
public static bool DeleteRouteFill(NetRoute template, string rule, int? metric = null)
|
||||
{
|
||||
if (!TryParseIPNetwork(rule, out var network, out var cidr))
|
||||
{
|
||||
Global.Logger.Warning($"invalid rule {rule}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return DeleteRoute(template.FillTemplate(network, (byte)cidr, metric));
|
||||
}
|
||||
|
||||
public static bool DeleteRoute(NetRoute o)
|
||||
{
|
||||
return RouteHelper.DeleteRoute(AddressFamily.InterNetwork, o.Network, o.Cidr, o.Gateway, (ulong)o.InterfaceIndex, o.Metric);
|
||||
}
|
||||
|
||||
public static bool TryParseIPNetwork(string ipNetwork, [NotNullWhen(true)] out string? ip, out int cidr)
|
||||
{
|
||||
ip = null;
|
||||
cidr = 0;
|
||||
|
||||
var s = ipNetwork.Split('/');
|
||||
if (s.Length != 2)
|
||||
return false;
|
||||
|
||||
ip = s[0];
|
||||
cidr = int.Parse(s[1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using Netch.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Range = Netch.Models.Range;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -30,9 +31,9 @@ namespace Netch.Utils
|
||||
public static class DelayTestHelper
|
||||
{
|
||||
private static readonly Timer Timer;
|
||||
private static bool _mux;
|
||||
private static readonly object TestAllLock = new();
|
||||
|
||||
public static readonly Range Range = new(0, int.MaxValue / 1000);
|
||||
public static readonly NumberRange Range = new(0, int.MaxValue / 1000);
|
||||
|
||||
static DelayTestHelper()
|
||||
{
|
||||
@@ -68,20 +69,22 @@ namespace Netch.Utils
|
||||
|
||||
public static void TestAllDelay()
|
||||
{
|
||||
if (_mux)
|
||||
if (!Monitor.TryEnter(TestAllLock))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_mux = true;
|
||||
Parallel.ForEach(Global.Settings.Server, new ParallelOptions { MaxDegreeOfParallelism = 16 }, server => { server.Test(); });
|
||||
_mux = false;
|
||||
TestDelayFinished?.Invoke(null, new EventArgs());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(TestAllLock);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateInterval()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using MaxMind.GeoIP2;
|
||||
using Microsoft.Win32.TaskScheduler;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
@@ -13,6 +11,8 @@ using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using MaxMind.GeoIP2;
|
||||
using Microsoft.Win32.TaskScheduler;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Netch.Utils
|
||||
@@ -201,6 +201,9 @@ namespace Netch.Utils
|
||||
|
||||
td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||
td.Settings.DisallowStartIfOnBatteries = false;
|
||||
td.Settings.StopIfGoingOnBatteries = false;
|
||||
td.Settings.IdleSettings.StopOnIdleEnd = false;
|
||||
td.Settings.IdleSettings.RestartOnIdle = false;
|
||||
td.Settings.RunOnlyIfIdle = false;
|
||||
td.Settings.Compatibility = TaskCompatibility.V2_1;
|
||||
|
||||
@@ -254,7 +257,7 @@ namespace Netch.Utils
|
||||
Console.Write(error);
|
||||
}
|
||||
|
||||
p.WaitForExit();
|
||||
await p.WaitForExitAsync();
|
||||
}
|
||||
|
||||
public static int SubnetToCidr(string value)
|
||||
@@ -275,5 +278,15 @@ namespace Netch.Utils
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
public static string GetHostFromUri(string str)
|
||||
{
|
||||
var startIndex = str.LastIndexOf('/');
|
||||
if (startIndex != -1)
|
||||
str = str[(startIndex + 1)..];
|
||||
|
||||
var endIndex = str.IndexOf(':');
|
||||
return endIndex == -1 ? str : str[..endIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
99
README.md
99
README.md
@@ -1,70 +1,55 @@
|
||||
<p align="center"><img src="https://cdn.jsdelivr.net/gh/netchx/netch/Netch/Resources/Netch.png" width="128" /></p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
# Netch
|
||||
[](https://t.me/Netch_Discuss_Group)
|
||||
[](https://t.me/Netch)
|
||||
[](https://github.com/NetchX/Netch)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/actions)
|
||||
[](LICENSE)
|
||||
A simple proxy client
|
||||
|
||||
[文档网站](https://netch.org/) [常见问题](https://netch.org/#/docs/zh-CN/faq)
|
||||
[](https://t.me/netch_group)
|
||||
[](https://t.me/netch_channel)
|
||||
[](https://github.com/netchx/netch/releases)
|
||||
[](https://github.com/netchx/netch/releases)
|
||||
</div>
|
||||
|
||||
[中文说明](README.zh-CN.md)
|
||||
## Features
|
||||
Some features may not be implemented in version 1
|
||||
|
||||
Game network accelerator
|
||||
### Modes
|
||||
- ProcessMode - Use Netfilter driver to intercept process traffic
|
||||
- ShareMode - Share your network based on WinPcap / Npcap
|
||||
- TapMode - Use TAP-Windows driver to create virtual adapter
|
||||
- TunMode - Use WinTUN driver to create virtual adapter
|
||||
- WebMode - Web proxy mode
|
||||
- WmpMode - Proxy forwarding (eg. OBS Streaming)
|
||||
|
||||
## TOC
|
||||
- [Netch](#netch)
|
||||
- [TOC](#toc)
|
||||
- [Description](#description)
|
||||
- [Sponsor](#sponsor)
|
||||
- [Donate](#donate)
|
||||
- [Screenshots](#screenshots)
|
||||
- [Requirements](#requirements)
|
||||
- [Quote](#quote)
|
||||
### Protocols
|
||||
- [Socks5](https://www.wikiwand.com/en/SOCKS)
|
||||
- [Shadowsocks](https://github.com/shadowsocks/shadowsocks-libev)
|
||||
- [ShadowsocksR](https://github.com/shadowsocksrr/shadowsocksr-libev)
|
||||
- [Trojan](https://trojan-gfw.github.io/trojan/)
|
||||
- [VLess](https://github.com/xtls/xray-core)
|
||||
- [VMess](https://github.com/v2fly/v2ray-core)
|
||||
|
||||
## Description
|
||||
Netch is an open source game network accelerator. Unlike SSTap, which needs to add rules to function as a blacklist proxy, Netch is more similar to SocksCap64, which can scan the game directory to get their process names specifically and forward their network traffic through the proxy server
|
||||
|
||||
Currently supports the following protocols
|
||||
- Socks5
|
||||
- Shadowsocks
|
||||
- ShadowsocksR
|
||||
- Trojan
|
||||
- VMess
|
||||
- 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
|
||||
### Others
|
||||
- UDP NAT FullCone (May limited by your server)
|
||||
- .NET 5.0 x64
|
||||
|
||||
## Sponsor
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="jetbrains.svg" alt="JetBrains" width="200"/></a>
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="https://cdn.jsdelivr.net/gh/netchx/netch/jetbrains.svg" alt="JetBrains" width="200"/></a>
|
||||
|
||||
- [RabbitHosts](https://rabbithosts.com/cart.php)
|
||||
- [ManSora](https://www.mansora.co/cart.php)
|
||||
- [NyanCat](https://nyancat.info/register)
|
||||
- [NeroCloud](https://nerocloud.io)
|
||||
|
||||
## Donate
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
- ETH *0x23dac0a93bcd71fec7a95833ad030338f167f185*
|
||||
|
||||
## Screenshots
|
||||

|
||||
|
||||
## Requirements
|
||||
- [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0/runtime)
|
||||
|
||||
## Quote
|
||||
- [core](https://github.com/aiocloud/core)
|
||||
- [aiodns](https://github.com/aiocloud/aiodns)
|
||||
- [tun2socks](https://github.com/aiocloud/tun2socks)
|
||||
- [Redirector](https://github.com/aiocloud/Redirector)
|
||||
- [RouteHelper](https://github.com/aiocloud/RouteHelper)
|
||||
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
|
||||
- [NetFilter SDK](https://netfiltersdk.com)
|
||||
- [pcap2socks](https://github.com/zhxie/pcap2socks)
|
||||
- [shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev)
|
||||
- [shadowsocksr-libev](https://github.com/shadowsocksrr/shadowsocksr-libev)
|
||||
- [trojan](https://github.com/trojan-gfw/trojan)
|
||||
- [xray-core](https://github.com/XTLS/Xray-core)
|
||||
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
|
||||
|
||||
[](https://starchart.cc/NetchX/Netch)
|
||||
## Credit
|
||||
- [WinTUN](https://www.wintun.net)
|
||||
- [aioCloud](https://github.com/aiocloud)
|
||||
- [NetFilter](https://netfiltersdk.com)
|
||||
- [TAP-Windows](https://github.com/OpenVPN/tap-windows6)
|
||||
- [Shadowsocks](https://github.com/shadowsocks/shadowsocks-libev)
|
||||
- [ShadowsocksR](https://github.com/shadowsocksrr/shadowsocksr-libev)
|
||||
- [Trojan](https://github.com/trojan-gfw/trojan)
|
||||
- [V2Ray](https://github.com/v2fly/v2ray-core)
|
||||
- [XRay](https://github.com/xtls/xray-core)
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
# Netch
|
||||
[](https://t.me/Netch_Discuss_Group)
|
||||
[](https://t.me/Netch)
|
||||
[](https://github.com/NetchX/Netch)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/actions)
|
||||
[](LICENSE)
|
||||
|
||||
[文档网站](https://netch.org/) [常见问题](https://netch.org/#/docs/zh-CN/faq)
|
||||
|
||||
游戏加速工具
|
||||
|
||||
## TOC
|
||||
- [Netch](#netch)
|
||||
- [TOC](#toc)
|
||||
- [简介](#简介)
|
||||
- [赞助商](#赞助商)
|
||||
- [捐赠](#捐赠)
|
||||
- [依赖](#依赖)
|
||||
- [语言支持](#语言支持)
|
||||
- [引用](#引用)
|
||||
|
||||
## 简介
|
||||
Netch 是一款 Windows 平台的开源游戏加速工具,Netch 可以实现类似 SocksCap64 那样的进程代理,也可以实现 SSTap 那样的全局 TUN/TAP 代理,和 Shadowsocks-Windows 那样的本地 Socks5,HTTP 和系统代理
|
||||
|
||||
至于连接至远程服务器的代理协议,目前 Netch 支持以下代理协议
|
||||
- Socks5
|
||||
- Shadowsocks
|
||||
- ShadowsocksR
|
||||
- Trojan
|
||||
- VMess
|
||||
- VLESS
|
||||
|
||||
与此同时 Netch 避免了 SSTap 的 NAT 问题 ,检查 NAT 类型即可知道是否有 NAT 问题。使用 SSTap 加速部分 P2P 联机,对 NAT 类型有要求的游戏时,可能会因为 NAT 类型严格遇到无法加入联机,或者其他影响游戏体验的情况
|
||||
|
||||
## 赞助商
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="jetbrains.svg" alt="JetBrains" width="200"/></a>
|
||||
|
||||
- [RabbitHosts](https://rabbithosts.com/cart.php)
|
||||
- [ManSora](https://www.mansora.co/cart.php)
|
||||
- [NyanCat](https://nyancat.info/register)
|
||||
|
||||
## 捐赠
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
|
||||
## 依赖
|
||||
- [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0/runtime)
|
||||
|
||||
## 语言支持
|
||||
Netch 内置 en-US 和 zh-CN,外置 zh-TW 等,默认根据系统语言选择语言。
|
||||
|
||||
[Netch 外置语言仓库](https://github.com/NetchX/NetchTranslation) ,欢迎提供其他语言的翻译
|
||||
|
||||
## 引用
|
||||
- [core](https://github.com/aiocloud/core)
|
||||
- [aiodns](https://github.com/aiocloud/aiodns)
|
||||
- [tun2socks](https://github.com/aiocloud/tun2socks)
|
||||
- [Redirector](https://github.com/aiocloud/Redirector)
|
||||
- [RouteHelper](https://github.com/aiocloud/RouteHelper)
|
||||
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
|
||||
- [NetFilter SDK](https://netfiltersdk.com)
|
||||
- [pcap2socks](https://github.com/zhxie/pcap2socks)
|
||||
- [shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev)
|
||||
- [shadowsocksr-libev](https://github.com/shadowsocksrr/shadowsocksr-libev)
|
||||
- [trojan](https://github.com/trojan-gfw/trojan)
|
||||
- [xray-core](https://github.com/XTLS/Xray-core)
|
||||
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
|
||||
|
||||
[](https://starchart.cc/NetchX/Netch)
|
||||
@@ -1,8 +1,8 @@
|
||||
param([string]$OutputPath)
|
||||
|
||||
$NetchDataURL="https://github.com/NetchX/NetchData/archive/refs/heads/master.zip"
|
||||
$NetchModeURL="https://github.com/NetchX/NetchMode/archive/refs/heads/master.zip"
|
||||
$NetchI18NURL="https://github.com/NetchX/NetchI18N/archive/refs/heads/master.zip"
|
||||
$NetchDataURL="https://github.com/netchx/netchdata/archive/refs/heads/master.zip"
|
||||
$NetchModeURL="https://github.com/netchx/netchmode/archive/refs/heads/master.zip"
|
||||
$NetchI18NURL="https://github.com/netchx/netchi18n/archive/refs/heads/master.zip"
|
||||
|
||||
$last=$(Get-Location)
|
||||
New-Item -ItemType Directory -Name $OutputPath | Out-Null
|
||||
@@ -20,19 +20,20 @@ New-Item -ItemType Directory -Name bin | Out-Null
|
||||
New-Item -ItemType Directory -Name mode | Out-Null
|
||||
New-Item -ItemType Directory -Name i18n | Out-Null
|
||||
|
||||
Copy-Item -Recurse -Force .\NetchData-master\* .\bin
|
||||
Copy-Item -Recurse -Force .\NetchMode-master\mode\* .\mode
|
||||
Copy-Item -Recurse -Force .\NetchI18N-master\i18n\* .\i18n
|
||||
Copy-Item -Recurse -Force .\netchdata-master\* .\bin
|
||||
Copy-Item -Recurse -Force .\netchmode-master\mode\* .\mode
|
||||
Copy-Item -Recurse -Force .\netchi18n-master\i18n\* .\i18n
|
||||
|
||||
Remove-Item -Recurse -Force NetchData-master
|
||||
Remove-Item -Recurse -Force NetchMode-master
|
||||
Remove-Item -Recurse -Force NetchI18N-master
|
||||
Remove-Item -Recurse -Force netchdata-master
|
||||
Remove-Item -Recurse -Force netchmode-master
|
||||
Remove-Item -Recurse -Force netchi18n-master
|
||||
Remove-Item -Force data.zip
|
||||
Remove-Item -Force mode.zip
|
||||
Remove-Item -Force i18n.zip
|
||||
|
||||
..\scripts\downloads\cloak.ps1 -OutputPath bin
|
||||
..\scripts\downloads\xray-core.ps1 -OutputPath bin
|
||||
..\scripts\download\aiodns.ps1 -OutputPath bin
|
||||
..\scripts\download\cloak.ps1 -OutputPath bin
|
||||
..\scripts\download\xray-core.ps1 -OutputPath bin
|
||||
|
||||
Get-Item *
|
||||
Set-Location $last
|
||||
|
||||
10
scripts/download/aiodns.ps1
Normal file
10
scripts/download/aiodns.ps1
Normal file
@@ -0,0 +1,10 @@
|
||||
param([string]$OutputPath)
|
||||
$address="https://github.com/aiocloud/aiodns/releases/download/1.0.4/aiodns.bin"
|
||||
$domains="https://raw.githubusercontent.com/aiocloud/aiodns/master/aiodns.conf"
|
||||
|
||||
Invoke-WebRequest -Uri $address -OutFile aiodns.bin
|
||||
Invoke-WebRequest -Uri $domains -OutFile aiodns.conf
|
||||
|
||||
Move-Item -Force aiodns.bin $OutputPath
|
||||
Move-Item -Force aiodns.conf $OutputPath
|
||||
exit 0
|
||||
@@ -1,5 +1,5 @@
|
||||
param([string]$OutputPath)
|
||||
$address="https://github.com/cbeuw/Cloak/releases/download/v2.5.3/ck-client-windows-amd64-v2.5.3.exe"
|
||||
$address="https://github.com/cbeuw/Cloak/releases/download/v2.5.4/ck-client-windows-amd64-v2.5.4.exe"
|
||||
|
||||
Invoke-WebRequest -Uri $address -OutFile ck-client.exe
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
param([string]$file)
|
||||
$hash = [Security.Cryptography.HashAlgorithm]::Create( "SHA256" )
|
||||
$path = (Resolve-Path -Path $file).Path
|
||||
$stream = ([IO.StreamReader]$path).BaseStream
|
||||
-join ($hash.ComputeHash($stream) | ForEach-Object { "{0:x2}" -f $_ })
|
||||
$stream.Close()
|
||||
(Get-FileHash $file -Algorithm SHA256).Hash.ToLower()
|
||||
|
||||
Reference in New Issue
Block a user