mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
95 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 | ||
|
|
6f1b0ee21f | ||
|
|
ce6d96a779 | ||
|
|
39f0f87b3a | ||
|
|
642c4d1af8 | ||
|
|
d42aa8f184 | ||
|
|
9c02ef353f | ||
|
|
1b4e7d41cc | ||
|
|
3d7dcbbffe | ||
|
|
be9d7d6845 | ||
|
|
a3620ed162 | ||
|
|
ba8c60675e | ||
|
|
c9a1265231 | ||
|
|
92b030ebd9 | ||
|
|
7fd24d46d3 | ||
|
|
e2f6a58fde | ||
|
|
5f31109bcf | ||
|
|
354608a72c | ||
|
|
5803b94ae9 | ||
|
|
ee7c6aa608 |
@@ -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
|
||||
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.cs text
|
||||
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/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Netch CI
|
||||
name: Netch Build CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Netch CI
|
||||
name: Netch Release CI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
@@ -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 自动化部署,更新日志应该很快会手动更新
|
||||
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
.vs/
|
||||
.idea/
|
||||
*/bin/
|
||||
*/obj/
|
||||
*.csproj.user
|
||||
/.vs
|
||||
/.vscode
|
||||
/.idea
|
||||
/release
|
||||
/DataCache
|
||||
50
Netch.sln
50
Netch.sln
@@ -1,25 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29009.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.Build.0 = Debug|x64
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.ActiveCfg = Release|x64
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6EC9B043-ACA5-4BB9-96DB-493A2EF6E43F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29009.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.Build.0 = Debug|x64
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.ActiveCfg = Release|x64
|
||||
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6EC9B043-ACA5-4BB9-96DB-493A2EF6E43F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
3
Netch/.gitignore
vendored
Normal file
3
Netch/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/bin
|
||||
/obj
|
||||
/*.csproj.user
|
||||
@@ -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}");
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -7,15 +9,13 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public abstract class Guard
|
||||
{
|
||||
private readonly Timer _flushFileStreamTimer = new(300) {AutoReset = true};
|
||||
private readonly Timer _flushFileStreamTimer = new(300) { AutoReset = true };
|
||||
|
||||
private FileStream? _logFileStream;
|
||||
|
||||
@@ -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,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
@@ -54,17 +55,17 @@ 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;
|
||||
|
||||
// 刷新DNS缓存
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
// 刷新 DNS 缓存
|
||||
NativeMethods.RefreshDNSCache();
|
||||
|
||||
if (DnsUtils.Lookup(server.Hostname) == null)
|
||||
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
|
||||
|
||||
// 添加Netch到防火墙
|
||||
// 添加 Netch 到防火墙
|
||||
Firewall.AddNetchFwRules();
|
||||
|
||||
try
|
||||
@@ -122,7 +123,7 @@ namespace Netch.Controllers
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName);
|
||||
|
||||
if (port != null)
|
||||
TryReleaseTcpPort((ushort) port, portName);
|
||||
TryReleaseTcpPort((ushort)port, portName);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -3,12 +3,13 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using static Netch.Interops.RedirectorInterop;
|
||||
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("!"))
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -6,8 +6,10 @@ 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
|
||||
{
|
||||
@@ -17,9 +19,7 @@ namespace Netch.Controllers
|
||||
|
||||
public override string MainFile { get; protected set; } = "pcap2socks.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"└"};
|
||||
|
||||
private readonly OutboundAdapter _outbound = new();
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "└" };
|
||||
|
||||
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
@@ -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,42 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using Vanara.PInvoke;
|
||||
using static Netch.Interops.TUNInterop;
|
||||
using static Vanara.PInvoke.Ws2_32;
|
||||
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
|
||||
@@ -80,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((int) AddressFamily.InterNetwork,
|
||||
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
Global.Settings.TUNTAP.Address,
|
||||
Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
|
||||
_tunAdapter.InterfaceIndex);
|
||||
(byte)Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
|
||||
(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)
|
||||
@@ -113,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)
|
||||
{
|
||||
@@ -121,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((int) AddressFamily.InterNetwork, ip, cidr, gateway, index, metric);
|
||||
if (result && record)
|
||||
ipList.Add(ipNetwork);
|
||||
|
||||
break;
|
||||
case Action.Delete:
|
||||
result = NativeMethods.DeleteRoute((int) AddressFamily.InterNetwork, ip, 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
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@@ -6,8 +8,6 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -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 = @"Beta114514";
|
||||
public const string AssemblyVersion = @"1.8.5";
|
||||
private const string Suffix = @"";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Netch.Controllers
|
||||
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
|
||||
|
||||
var releases = JsonSerializer.Deserialize<List<Release>>(json)!;
|
||||
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
|
||||
LatestRelease = GetLatestRelease(releases, isPreRelease);
|
||||
Global.Logger.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
|
||||
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
|
||||
{
|
||||
@@ -104,5 +104,14 @@ namespace Netch.Controllers
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
|
||||
{
|
||||
if (!isPreRelease)
|
||||
releases = releases.Where(release => !release.prerelease);
|
||||
|
||||
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionUtil.VersionComparer());
|
||||
return ordered.ElementAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -21,17 +21,17 @@ namespace Netch.Forms
|
||||
|
||||
private void NetchPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
Process.Start("https://github.com/NetchX/Netch");
|
||||
Utils.Utils.Open("https://github.com/NetchX/Netch");
|
||||
}
|
||||
|
||||
private void ChannelLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
Process.Start("https://t.me/Netch");
|
||||
Utils.Utils.Open("https://t.me/Netch");
|
||||
}
|
||||
|
||||
private void SponsorPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
Process.Start("https://www.mansora.co");
|
||||
Utils.Utils.Open("https://www.mansora.co");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -54,7 +54,7 @@ namespace Netch.Forms
|
||||
{
|
||||
Global.Settings.TUNTAP.BypassIPs.Clear();
|
||||
foreach (var ip in IPListBox.Items)
|
||||
Global.Settings.TUNTAP.BypassIPs.Add((string) ip);
|
||||
Global.Settings.TUNTAP.BypassIPs.Add((string)ip);
|
||||
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
using Microsoft.Win32;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -8,24 +14,15 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
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();
|
||||
@@ -41,14 +38,12 @@ namespace Netch.Forms
|
||||
|
||||
#region i18N Translations
|
||||
|
||||
_mainFormText.Add(UninstallServiceToolStripMenuItem.Name, new[] {"Uninstall {0}", "NF Service"});
|
||||
_mainFormText.Add(UninstallServiceToolStripMenuItem.Name, new[] { "Uninstall {0}", "NF Service" });
|
||||
|
||||
#endregion
|
||||
|
||||
// 监听电源事件
|
||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
||||
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
}
|
||||
|
||||
private void AddAddServerToolStripMenuItems()
|
||||
@@ -60,10 +55,11 @@ 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});
|
||||
_mainFormText.Add(control.Name, new[] { "Add [{0}] Server", fullName });
|
||||
control.Click += AddServerToolStripMenuItem_Click;
|
||||
ServerToolStripMenuItem.DropDownItems.Add(control);
|
||||
}
|
||||
@@ -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()
|
||||
@@ -184,7 +180,7 @@ namespace Netch.Forms
|
||||
return string.Empty;
|
||||
|
||||
if (value is object[] values)
|
||||
return i18N.TranslateFormat((string) values.First(), values.Skip(1).ToArray());
|
||||
return i18N.TranslateFormat((string)values.First(), values.Skip(1).ToArray());
|
||||
|
||||
return i18N.Translate(value);
|
||||
}
|
||||
@@ -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)
|
||||
@@ -348,7 +343,7 @@ namespace Netch.Forms
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
NativeMethods.RefreshDNSCache();
|
||||
DnsUtils.ClearCache();
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
@@ -704,7 +699,7 @@ namespace Netch.Forms
|
||||
{
|
||||
try
|
||||
{
|
||||
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode) ModeComboBox.SelectedItem);
|
||||
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode)ModeComboBox.SelectedItem);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -721,7 +716,7 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
var mode = (Models.Mode)ModeComboBox.SelectedItem;
|
||||
if (ModifierKeys == Keys.Control)
|
||||
{
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath!));
|
||||
@@ -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();
|
||||
@@ -756,7 +751,7 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
ModeHelper.Delete((Models.Mode) ModeComboBox.SelectedItem);
|
||||
ModeHelper.Delete((Models.Mode)ModeComboBox.SelectedItem);
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
@@ -773,7 +768,7 @@ namespace Netch.Forms
|
||||
{
|
||||
// Clear
|
||||
foreach (var button in ProfileTable.Controls)
|
||||
((Button) button).Dispose();
|
||||
((Button)button).Dispose();
|
||||
|
||||
ProfileTable.Controls.Clear();
|
||||
ProfileTable.ColumnStyles.Clear();
|
||||
@@ -799,7 +794,7 @@ namespace Netch.Forms
|
||||
var columnCount = Global.Settings.ProfileTableColumnCount;
|
||||
|
||||
ProfileTable.ColumnCount = profileCount >= columnCount ? columnCount : profileCount;
|
||||
ProfileTable.RowCount = (int) Math.Ceiling(profileCount / (float) columnCount);
|
||||
ProfileTable.RowCount = (int)Math.Ceiling(profileCount / (float)columnCount);
|
||||
|
||||
for (var i = 0; i < profileCount; ++i)
|
||||
{
|
||||
@@ -848,8 +843,8 @@ namespace Netch.Forms
|
||||
|
||||
private Profile CreateProfileAtIndex(int index)
|
||||
{
|
||||
var server = (Server) ServerComboBox.SelectedItem;
|
||||
var mode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
var server = (Server)ServerComboBox.SelectedItem;
|
||||
var mode = (Models.Mode)ModeComboBox.SelectedItem;
|
||||
var name = ProfileNameText.Text;
|
||||
|
||||
Profile? profile;
|
||||
@@ -866,8 +861,8 @@ namespace Netch.Forms
|
||||
if (sender == null)
|
||||
throw new ArgumentNullException(nameof(sender));
|
||||
|
||||
var profileButton = (Button) sender;
|
||||
var profile = (Profile?) profileButton.Tag;
|
||||
var profileButton = (Button)sender;
|
||||
var profile = (Profile?)profileButton.Tag;
|
||||
var index = ProfileTable.Controls.IndexOf(profileButton);
|
||||
|
||||
switch (ModifierKeys)
|
||||
@@ -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()
|
||||
@@ -1107,13 +1096,13 @@ namespace Netch.Forms
|
||||
{
|
||||
NatTypeStatusLightLabel.Visible = Flags.IsWindows10Upper;
|
||||
var c = natType switch
|
||||
{
|
||||
1 => Color.LimeGreen,
|
||||
2 => Color.Yellow,
|
||||
3 => Color.Red,
|
||||
4 => Color.Black,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(natType), natType, null)
|
||||
};
|
||||
{
|
||||
1 => Color.LimeGreen,
|
||||
2 => Color.Yellow,
|
||||
3 => Color.Red,
|
||||
4 => Color.Black,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(natType), natType, null)
|
||||
};
|
||||
|
||||
NatTypeStatusLightLabel.ForeColor = c;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1231,12 +1227,11 @@ namespace Netch.Forms
|
||||
Configuration.Save();
|
||||
}
|
||||
|
||||
foreach (var file in new[] {"data\\last.json", "data\\privoxy.conf"})
|
||||
foreach (var file in new[] { "data\\last.json", "data\\privoxy.conf" })
|
||||
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;
|
||||
|
||||
// 绘制背景颜色
|
||||
@@ -1403,7 +1398,7 @@ namespace Netch.Forms
|
||||
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);
|
||||
@@ -1425,7 +1420,7 @@ namespace Netch.Forms
|
||||
|
||||
// 绘制 模式行数 字符串
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Rule.Count.ToString(),
|
||||
item.Content.Count.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -23,20 +23,20 @@ namespace Netch.Forms
|
||||
MessageBoxIcon msgIcon;
|
||||
if (string.IsNullOrWhiteSpace(title))
|
||||
title = level switch
|
||||
{
|
||||
LogLevel.INFO => "Information",
|
||||
LogLevel.WARNING => "Warning",
|
||||
LogLevel.ERROR => "Error",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
{
|
||||
LogLevel.INFO => "Information",
|
||||
LogLevel.WARNING => "Warning",
|
||||
LogLevel.ERROR => "Error",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
|
||||
msgIcon = level switch
|
||||
{
|
||||
LogLevel.INFO => MessageBoxIcon.Information,
|
||||
LogLevel.WARNING => MessageBoxIcon.Warning,
|
||||
LogLevel.ERROR => MessageBoxIcon.Exclamation,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
{
|
||||
LogLevel.INFO => MessageBoxIcon.Information,
|
||||
LogLevel.WARNING => MessageBoxIcon.Warning,
|
||||
LogLevel.ERROR => MessageBoxIcon.Exclamation,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
|
||||
return MessageBox.Show(owner, text, i18N.Translate(title), confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK, msgIcon);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
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"));
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
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"));
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#nullable disable
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -38,13 +38,13 @@ namespace Netch.Forms
|
||||
InitializeComponent();
|
||||
|
||||
_checkActions.Add(RemarkTextBox, s => true);
|
||||
_saveActions.Add(RemarkTextBox, s => Server.Remark = (string) s);
|
||||
_saveActions.Add(RemarkTextBox, s => Server.Remark = (string)s);
|
||||
|
||||
_checkActions.Add(AddressTextBox, s => s != string.Empty);
|
||||
_saveActions.Add(AddressTextBox, s => Server.Hostname = (string) s);
|
||||
_saveActions.Add(AddressTextBox, s => Server.Hostname = (string)s);
|
||||
|
||||
_checkActions.Add(PortTextBox, s => ushort.TryParse(s, out var port) && port != 0);
|
||||
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string) s));
|
||||
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string)s));
|
||||
}
|
||||
|
||||
protected abstract string TypeName { get; }
|
||||
@@ -99,7 +99,7 @@ namespace Netch.Forms
|
||||
};
|
||||
|
||||
_checkActions.Add(textBox, check);
|
||||
_saveActions.Add(textBox, o => save.Invoke((string) o));
|
||||
_saveActions.Add(textBox, o => save.Invoke((string)o));
|
||||
ConfigurationGroupBox.Controls.AddRange(new Control[]
|
||||
{
|
||||
textBox,
|
||||
@@ -131,7 +131,7 @@ namespace Netch.Forms
|
||||
comboBox.Items.AddRange(values.ToArray());
|
||||
comboBox.SelectedIndex = values.IndexOf(value);
|
||||
comboBox.DrawItem += Utils.Utils.DrawCenterComboBox;
|
||||
_saveActions.Add(comboBox, o => save.Invoke((string) o));
|
||||
_saveActions.Add(comboBox, o => save.Invoke((string)o));
|
||||
ConfigurationGroupBox.Controls.AddRange(new Control[]
|
||||
{
|
||||
comboBox,
|
||||
@@ -159,7 +159,7 @@ namespace Netch.Forms
|
||||
Text = remark
|
||||
};
|
||||
|
||||
_saveActions.Add(checkBox, o => save.Invoke((bool) o));
|
||||
_saveActions.Add(checkBox, o => save.Invoke((bool)o));
|
||||
ConfigurationGroupBox.Controls.AddRange(new Control[]
|
||||
{
|
||||
checkBox
|
||||
|
||||
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;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
@@ -5,9 +8,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -37,7 +37,7 @@ namespace Netch.Forms
|
||||
|
||||
BindCheckBox(AllowDevicesCheckBox,
|
||||
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
|
||||
Global.Settings.LocalAddress switch {"127.0.0.1" => false, "0.0.0.0" => true, _ => false});
|
||||
Global.Settings.LocalAddress switch { "127.0.0.1" => false, "0.0.0.0" => true, _ => false });
|
||||
|
||||
BindCheckBox(ResolveServerHostnameCheckBox, c => Global.Settings.ResolveServerHostname = c, Global.Settings.ResolveServerHostname);
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace Netch.Forms
|
||||
Global.Settings.Redirector.ChildProcessHandle);
|
||||
|
||||
BindListComboBox(ProcessProxyProtocolComboBox,
|
||||
s => Global.Settings.Redirector.ProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
s => Global.Settings.Redirector.ProxyProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)),
|
||||
Global.Settings.Redirector.ProxyProtocol.ToString());
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -284,7 +287,7 @@ namespace Netch.Forms
|
||||
{
|
||||
try
|
||||
{
|
||||
return check.Invoke((T) Convert.ChangeType(s, typeof(T)));
|
||||
return check.Invoke((T)Convert.ChangeType(s, typeof(T)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -292,19 +295,19 @@ namespace Netch.Forms
|
||||
}
|
||||
});
|
||||
|
||||
_saveActions.Add(control, c => save.Invoke((T) Convert.ChangeType(((TextBox) c).Text, typeof(T))));
|
||||
_saveActions.Add(control, c => save.Invoke((T)Convert.ChangeType(((TextBox)c).Text, typeof(T))));
|
||||
}
|
||||
|
||||
private void BindCheckBox(CheckBox control, Action<bool> save, bool value)
|
||||
{
|
||||
control.Checked = value;
|
||||
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
|
||||
_saveActions.Add(control, c => save.Invoke(((CheckBox)c).Checked));
|
||||
}
|
||||
|
||||
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
|
||||
{
|
||||
control.Checked = value;
|
||||
_saveActions.Add(control, c => save.Invoke(((RadioButton) c).Checked));
|
||||
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
|
||||
}
|
||||
|
||||
private void BindListComboBox<T>(ComboBox comboBox, Action<T> save, IEnumerable<T> values, T value) where T : notnull
|
||||
@@ -318,7 +321,7 @@ namespace Netch.Forms
|
||||
comboBox.ValueMember = nameof(TagItem<T>.Value);
|
||||
comboBox.DisplayMember = nameof(TagItem<T>.Text);
|
||||
|
||||
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>) ((ComboBox) c).SelectedItem).Value));
|
||||
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>)((ComboBox)c).SelectedItem).Value));
|
||||
Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); };
|
||||
}
|
||||
|
||||
@@ -327,7 +330,7 @@ namespace Netch.Forms
|
||||
if (values != null)
|
||||
control.Items.AddRange(values);
|
||||
|
||||
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).Text));
|
||||
_saveActions.Add(control, c => save.Invoke(((ComboBox)c).Text));
|
||||
_checkActions.Add(control, check.Invoke);
|
||||
|
||||
Load += (_, _) => { control.Text = value; };
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Models.Loggers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Forms;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Models.Loggers;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
|
||||
@@ -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 System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class RedirectorInterop
|
||||
public static class Redirector
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
@@ -43,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);
|
||||
}
|
||||
|
||||
@@ -57,7 +56,7 @@ namespace Netch.Interops
|
||||
return aio_free();
|
||||
}
|
||||
|
||||
public const int UdpNameListOffset = (int) NameList.TYPE_UDPLISN - (int) NameList.TYPE_TCPLISN;
|
||||
public const int UdpNameListOffset = (int)NameList.TYPE_UDPLISN - (int)NameList.TYPE_TCPLISN;
|
||||
|
||||
private const string Redirector_bin = "Redirector.bin";
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class TUNInterop
|
||||
public static class tun2socks
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
@@ -36,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();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
@@ -8,28 +9,53 @@ namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
public Version Version { get; }
|
||||
|
||||
public string Suffix { get; }
|
||||
public string? Suffix { get; }
|
||||
|
||||
public SuffixVersion(Version version, string suffix)
|
||||
public int SuffixNum { get; }
|
||||
|
||||
private SuffixVersion(Version version)
|
||||
{
|
||||
Version = version;
|
||||
Suffix = null;
|
||||
SuffixNum = 0;
|
||||
}
|
||||
|
||||
private SuffixVersion(Version version, string suffix, int suffixNum)
|
||||
{
|
||||
Version = version;
|
||||
Suffix = suffix;
|
||||
SuffixNum = suffixNum;
|
||||
}
|
||||
|
||||
public static SuffixVersion Parse(string? input)
|
||||
public static SuffixVersion Parse(string? value)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
var split = input.Split('-');
|
||||
var dotNetVersion = Version.Parse(split[0]);
|
||||
var preRelease = split.ElementAtOrDefault(1) ?? string.Empty;
|
||||
var strings = value.Split('-');
|
||||
|
||||
return new SuffixVersion(dotNetVersion, preRelease);
|
||||
var version = Version.Parse(strings[0]);
|
||||
var suffix = strings.ElementAtOrDefault(1)?.Trim();
|
||||
switch (suffix)
|
||||
{
|
||||
case null:
|
||||
return new SuffixVersion(version);
|
||||
case "":
|
||||
throw new Exception("suffix WhiteSpace");
|
||||
default:
|
||||
{
|
||||
var match = Regex.Match(suffix, @"(?<suffix>\D+)(?<num>\d+)");
|
||||
if (!match.Success)
|
||||
throw new Exception();
|
||||
|
||||
return new SuffixVersion(version, match.Groups["suffix"].Value, int.Parse(match.Groups["num"].Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryParse(string input, out SuffixVersion result)
|
||||
public static bool TryParse(string? input, out SuffixVersion result)
|
||||
{
|
||||
result = default;
|
||||
try
|
||||
{
|
||||
result = Parse(input);
|
||||
@@ -37,7 +63,6 @@ namespace Netch.Models.GitHubRelease
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -62,21 +87,22 @@ namespace Netch.Models.GitHubRelease
|
||||
if (versionComparison != 0)
|
||||
return versionComparison;
|
||||
|
||||
if (Suffix == string.Empty)
|
||||
return other.Suffix == string.Empty ? 0 : 1;
|
||||
|
||||
if (other.Suffix == string.Empty)
|
||||
return -1;
|
||||
var suffixExistComparison = (Suffix == null ? 1 : 0) - (other.Suffix == null ? 1 : 0);
|
||||
if (suffixExistComparison != 0)
|
||||
return suffixExistComparison;
|
||||
|
||||
var suffixComparison = string.Compare(Suffix, other.Suffix, StringComparison.OrdinalIgnoreCase);
|
||||
return suffixComparison;
|
||||
if (suffixComparison != 0)
|
||||
return suffixComparison;
|
||||
|
||||
return SuffixNum - other.SuffixNum;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var s = Version.ToString();
|
||||
if (Suffix != string.Empty)
|
||||
s += $"-{Suffix}";
|
||||
if (Suffix != null)
|
||||
s += $"-{Suffix}{SuffixNum}";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
public class VersionComparer : IComparer<object>
|
||||
{
|
||||
public int Compare(object? x, object? y)
|
||||
{
|
||||
if (x == null)
|
||||
throw new ArgumentNullException(nameof(x));
|
||||
|
||||
if (y == null)
|
||||
throw new ArgumentNullException(nameof(y));
|
||||
|
||||
return VersionUtil.CompareVersion(x.ToString(), y.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
public static class VersionUtil
|
||||
{
|
||||
public static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
|
||||
{
|
||||
if (!isPreRelease)
|
||||
releases = releases.Where(release => !release.prerelease);
|
||||
private static VersionComparer instance = new();
|
||||
|
||||
releases = releases.Where(release => IsVersionString(release.tag_name));
|
||||
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionComparer());
|
||||
return ordered.ElementAt(0);
|
||||
public static int CompareVersion(string x, string y)
|
||||
{
|
||||
return instance.Compare(x, y);
|
||||
}
|
||||
|
||||
private static bool IsVersionString(string str)
|
||||
public class VersionComparer : IComparer<string>
|
||||
{
|
||||
return SuffixVersion.TryParse(str, out _);
|
||||
}
|
||||
/// <summary>
|
||||
/// Greater than 0 newer
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
public int Compare(string? x, string? y)
|
||||
{
|
||||
var xResult = SuffixVersion.TryParse(x, out var version1) ? 1 : 0;
|
||||
var yResult = SuffixVersion.TryParse(y, out var version2) ? 1 : 0;
|
||||
|
||||
/// <returns> =0:versions are equal</returns>
|
||||
/// <returns> >0:version1 is greater</returns>
|
||||
/// <returns> <0:version2 is greater</returns>
|
||||
public static int CompareVersion(string? v1, string? v2)
|
||||
{
|
||||
var version1 = SuffixVersion.Parse(v1);
|
||||
var version2 = SuffixVersion.Parse(v2);
|
||||
return version1.CompareTo(version2);
|
||||
var parseResult = xResult - yResult;
|
||||
if (parseResult != 0)
|
||||
return parseResult;
|
||||
|
||||
return version1.CompareTo(version2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public interface IAdapter
|
||||
{
|
||||
int InterfaceIndex { get; }
|
||||
|
||||
IPAddress Gateway { get; }
|
||||
|
||||
NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace Netch.Models.Loggers
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using Netch.Interfaces;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Netch.Interfaces;
|
||||
|
||||
namespace Netch.Models.Loggers
|
||||
{
|
||||
public class FileLogger : ILogger
|
||||
{
|
||||
public string LogFile { get; set; }= Path.Combine(Global.NetchDir, "logging\\application.log");
|
||||
public string LogFile { get; set; } = Path.Combine(Global.NetchDir, "logging\\application.log");
|
||||
|
||||
private readonly object _fileLock = new();
|
||||
|
||||
|
||||
@@ -1,141 +1,129 @@
|
||||
using System;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Utils;
|
||||
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,46 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Utils;
|
||||
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 = (int) 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 int InterfaceIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Utils;
|
||||
using Netch.Utils;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -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
|
||||
@@ -265,7 +263,7 @@ namespace Netch.Models
|
||||
|
||||
public Setting Clone()
|
||||
{
|
||||
return (Setting) MemberwiseClone();
|
||||
return (Setting)MemberwiseClone();
|
||||
}
|
||||
|
||||
public void Set(Setting value)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Netch.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Interops;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class TunAdapter : IAdapter
|
||||
{
|
||||
public TunAdapter()
|
||||
{
|
||||
InterfaceIndex = (int) NativeMethods.ConvertLuidToIndex(TUNInterop.tun_luid());
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.GetIPProperties().GetIPv4Properties().Index == InterfaceIndex);
|
||||
Gateway = IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
|
||||
|
||||
Global.Logger.Info($"WinTUN 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
|
||||
}
|
||||
|
||||
|
||||
public int InterfaceIndex { get; }
|
||||
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,47 +4,7 @@ namespace Netch
|
||||
{
|
||||
public static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// 分配 IP 地址
|
||||
/// </summary>
|
||||
/// <param name="inet">AF_INET / AF_INET6</param>
|
||||
/// <param name="address">目标地址</param>
|
||||
/// <param name="cidr">CIDR</param>
|
||||
/// <param name="index">适配器索引</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateUnicastIP")]
|
||||
public static extern bool CreateUnicastIP(int inet, string address, int cidr, int index);
|
||||
|
||||
/// <summary>
|
||||
/// 创建路由规则
|
||||
/// </summary>
|
||||
/// <param name="inet">AF_INET / AF_INET6</param>
|
||||
/// <param name="address">目标地址</param>
|
||||
/// <param name="cidr">CIDR</param>
|
||||
/// <param name="gateway">网关地址</param>
|
||||
/// <param name="index">适配器索引</param>
|
||||
/// <param name="metric">跃点数</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateRoute")]
|
||||
public static extern bool CreateRoute(int inet, string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 删除路由规则
|
||||
/// </summary>
|
||||
/// <param name="inet">AF_INET / AF_INET6</param>
|
||||
/// <param name="address">目标地址</param>
|
||||
/// <param name="cidr">掩码地址</param>
|
||||
/// <param name="gateway">网关地址</param>
|
||||
/// <param name="index">适配器索引</param>
|
||||
/// <param name="metric">跃点数</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
|
||||
public static extern bool DeleteRoute(int inet, string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong ConvertLuidToIndex(ulong luid);
|
||||
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint FlushDNSResolverCache();
|
||||
public static extern uint RefreshDNSCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using System;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using Netch.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using Vanara.PInvoke;
|
||||
using static Vanara.PInvoke.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,10 +40,10 @@ 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"};
|
||||
var directories = new[] { "mode\\Custom", "data", "i18n", "logging" };
|
||||
foreach (var item in directories)
|
||||
if (!Directory.Exists(item))
|
||||
Directory.CreateDirectory(item);
|
||||
@@ -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,7 +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>
|
||||
@@ -39,32 +39,22 @@
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove=".gitignore" />
|
||||
<None Visible="false" Include="..\binaries\**" LinkBase="bin" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Update="..\binaries\NTT.exe">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</None>
|
||||
<None Remove="..\binaries\.git" />
|
||||
<None Visible="false" Include="..\translations\i18n\**" LinkBase="i18n" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<None Visible="false" Include="..\modes\mode\**" LinkBase="mode" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
@@ -100,5 +90,4 @@
|
||||
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\TraceReloggerLib.dll" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
using Netch.Controllers;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Netch.Controllers;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
|
||||
@@ -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,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
@@ -8,9 +9,9 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"listening at"};
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "listening at" };
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"Invalid config path", "usage", "plugin service exit unexpectedly"};
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "Invalid config path", "usage", "plugin service exit unexpectedly" };
|
||||
|
||||
public override string Name { get; } = "Shadowsocks";
|
||||
|
||||
@@ -20,7 +21,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
var server = (Shadowsocks)s;
|
||||
|
||||
var command = new SSParameter
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks.Form;
|
||||
using Netch.Servers.Shadowsocks.Models.SSD;
|
||||
@@ -22,13 +22,13 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public string ShortName { get; } = "SS";
|
||||
|
||||
public string[] UriScheme { get; } = {"ss", "ssd"};
|
||||
public string[] UriScheme { get; } = { "ss", "ssd" };
|
||||
|
||||
public Type ServerType { get; } = typeof(Shadowsocks);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksForm((Shadowsocks) s).ShowDialog();
|
||||
new ShadowsocksForm((Shadowsocks)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -38,7 +38,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
var server = (Shadowsocks)s;
|
||||
// ss://method:password@server:port#Remark
|
||||
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" +
|
||||
HttpUtility.UrlEncode(server.Remark);
|
||||
@@ -52,7 +52,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
if (text.StartsWith("ss://"))
|
||||
return new[] {ParseSsUri(text)};
|
||||
return new[] { ParseSsUri(text) };
|
||||
|
||||
if (text.StartsWith("ssd://"))
|
||||
return ParseSsdUri(text);
|
||||
@@ -62,7 +62,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
var server = (Shadowsocks)s;
|
||||
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Global.Logger.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
@@ -79,17 +79,17 @@ namespace Netch.Servers.Shadowsocks
|
||||
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
|
||||
|
||||
return json.servers.Select(server => new Shadowsocks
|
||||
{
|
||||
Remark = server.remarks,
|
||||
Hostname = server.server,
|
||||
Port = server.port != 0 ? server.port : json.port,
|
||||
Password = server.password ?? json.password,
|
||||
EncryptMethod = server.encryption ?? json.encryption,
|
||||
Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin,
|
||||
PluginOption = string.IsNullOrEmpty(json.plugin_options)
|
||||
{
|
||||
Remark = server.remarks,
|
||||
Hostname = server.server,
|
||||
Port = server.port != 0 ? server.port : json.port,
|
||||
Password = server.password ?? json.password,
|
||||
EncryptMethod = server.encryption ?? json.encryption,
|
||||
Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin,
|
||||
PluginOption = string.IsNullOrEmpty(json.plugin_options)
|
||||
? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options
|
||||
: json.plugin_options
|
||||
})
|
||||
})
|
||||
.Where(CheckServer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
@@ -8,9 +9,9 @@ namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "ShadowsocksR.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"listening at"};
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "listening at" };
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"Invalid config path", "usage"};
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "Invalid config path", "usage" };
|
||||
|
||||
public override string Name { get; } = "ShadowsocksR";
|
||||
|
||||
@@ -20,7 +21,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
var server = (ShadowsocksR)s;
|
||||
|
||||
var command = new SSRParameter
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.ShadowsocksR.Form;
|
||||
@@ -19,13 +19,13 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public string ShortName { get; } = "SR";
|
||||
|
||||
public string[] UriScheme { get; } = {"ssr"};
|
||||
public string[] UriScheme { get; } = { "ssr" };
|
||||
|
||||
public Type ServerType { get; } = typeof(ShadowsocksR);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksRForm((ShadowsocksR) s).ShowDialog();
|
||||
new ShadowsocksRForm((ShadowsocksR)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -35,7 +35,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
var server = (ShadowsocksR)s;
|
||||
|
||||
// https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
|
||||
// ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
||||
@@ -143,7 +143,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
var server = (ShadowsocksR)s;
|
||||
if (!SSRGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Global.Logger.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Netch.Servers.Socks5
|
||||
|
||||
public override void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (Socks5) s;
|
||||
var server = (Socks5)s;
|
||||
if (server.Auth())
|
||||
base.Start(s, mode);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5.Form;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Netch.Servers.Socks5
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new Socks5Form((Socks5) s).ShowDialog();
|
||||
new Socks5Form((Socks5)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -33,7 +33,7 @@ namespace Netch.Servers.Socks5
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (Socks5) s;
|
||||
var server = (Socks5)s;
|
||||
// https://t.me/socks?server=1.1.1.1&port=443
|
||||
return $"https://t.me/socks?server={server.Hostname}&port={server.Port}" +
|
||||
$"{(!string.IsNullOrWhiteSpace(server.Username) ? $"&user={server.Username}" : "")}" +
|
||||
@@ -68,7 +68,7 @@ namespace Netch.Servers.Socks5
|
||||
if (dict.ContainsKey("pass") && !string.IsNullOrWhiteSpace(dict["pass"]))
|
||||
data.Password = dict["pass"];
|
||||
|
||||
return new[] {data};
|
||||
return new[] { data };
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Models;
|
||||
|
||||
@@ -11,9 +12,9 @@ namespace Netch.Servers.Trojan
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "Trojan.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"started"};
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "started" };
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"exiting"};
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "exiting" };
|
||||
|
||||
public override string Name { get; } = "Trojan";
|
||||
|
||||
@@ -23,7 +24,7 @@ namespace Netch.Servers.Trojan
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (Trojan) s;
|
||||
var server = (Trojan)s;
|
||||
var trojanConfig = new TrojanConfig
|
||||
{
|
||||
local_addr = this.LocalAddress(),
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Trojan.Form;
|
||||
|
||||
@@ -18,13 +18,13 @@ namespace Netch.Servers.Trojan
|
||||
|
||||
public string ShortName { get; } = "TR";
|
||||
|
||||
public string[] UriScheme { get; } = {"trojan"};
|
||||
public string[] UriScheme { get; } = { "trojan" };
|
||||
|
||||
public Type ServerType { get; } = typeof(Trojan);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new TrojanForm((Trojan) s).ShowDialog();
|
||||
new TrojanForm((Trojan)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -34,7 +34,7 @@ namespace Netch.Servers.Trojan
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (Trojan) s;
|
||||
var server = (Trojan)s;
|
||||
return $"trojan://{HttpUtility.UrlEncode(server.Password)}@{server.Hostname}:{server.Port}#{server.Remark}";
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Netch.Servers.Trojan
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
return new[] {data};
|
||||
return new[] { data };
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
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)
|
||||
@@ -109,8 +110,8 @@ namespace Netch.Servers.V2ray.Utils
|
||||
switch (server)
|
||||
{
|
||||
case Socks5.Socks5 socks5:
|
||||
{
|
||||
outbound.settings.servers = new List<ServersItem>
|
||||
{
|
||||
outbound.settings.servers = new List<ServersItem>
|
||||
{
|
||||
new()
|
||||
{
|
||||
@@ -130,80 +131,80 @@ namespace Netch.Servers.V2ray.Utils
|
||||
}
|
||||
};
|
||||
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
outbound.protocol = "socks";
|
||||
break;
|
||||
}
|
||||
case VLESS.VLESS vless:
|
||||
{
|
||||
var vnextItem = new VnextItem
|
||||
{
|
||||
users = new List<UsersItem>(),
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
|
||||
outbound.settings.vnext = new List<VnextItem> {vnextItem};
|
||||
|
||||
var usersItem = new UsersItem
|
||||
{
|
||||
id = vless.UserID,
|
||||
alterId = 0,
|
||||
flow = string.Empty,
|
||||
encryption = vless.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
boundStreamSettings(vless, ref streamSettings);
|
||||
|
||||
if (vless.TLSSecureType == "xtls")
|
||||
{
|
||||
usersItem.flow = string.IsNullOrEmpty(vless.Flow) ? "xtls-rprx-origin" : vless.Flow;
|
||||
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
outbound.protocol = "socks";
|
||||
break;
|
||||
}
|
||||
else
|
||||
case VLESS.VLESS vless:
|
||||
{
|
||||
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
|
||||
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
|
||||
}
|
||||
var vnextItem = new VnextItem
|
||||
{
|
||||
users = new List<UsersItem>(),
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
|
||||
outbound.protocol = "vless";
|
||||
outbound.settings.servers = null;
|
||||
break;
|
||||
}
|
||||
outbound.settings.vnext = new List<VnextItem> { vnextItem };
|
||||
|
||||
var usersItem = new UsersItem
|
||||
{
|
||||
id = vless.UserID,
|
||||
alterId = 0,
|
||||
flow = string.Empty,
|
||||
encryption = vless.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
boundStreamSettings(vless, ref streamSettings);
|
||||
|
||||
if (vless.TLSSecureType == "xtls")
|
||||
{
|
||||
usersItem.flow = string.IsNullOrEmpty(vless.Flow) ? "xtls-rprx-origin" : vless.Flow;
|
||||
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
|
||||
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
|
||||
}
|
||||
|
||||
outbound.protocol = "vless";
|
||||
outbound.settings.servers = null;
|
||||
break;
|
||||
}
|
||||
case VMess.VMess vmess:
|
||||
{
|
||||
var vnextItem = new VnextItem
|
||||
{
|
||||
users = new List<UsersItem>(),
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
var vnextItem = new VnextItem
|
||||
{
|
||||
users = new List<UsersItem>(),
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
|
||||
outbound.settings.vnext = new List<VnextItem> {vnextItem};
|
||||
outbound.settings.vnext = new List<VnextItem> { vnextItem };
|
||||
|
||||
var usersItem = new UsersItem
|
||||
{
|
||||
id = vmess.UserID,
|
||||
alterId = vmess.AlterID,
|
||||
security = vmess.EncryptMethod
|
||||
};
|
||||
var usersItem = new UsersItem
|
||||
{
|
||||
id = vmess.UserID,
|
||||
alterId = vmess.AlterID,
|
||||
security = vmess.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.users.Add(usersItem);
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
boundStreamSettings(vmess, ref streamSettings);
|
||||
var streamSettings = outbound.streamSettings;
|
||||
boundStreamSettings(vmess, ref streamSettings);
|
||||
|
||||
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
|
||||
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
|
||||
outbound.protocol = "vmess";
|
||||
break;
|
||||
}
|
||||
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
|
||||
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
|
||||
outbound.protocol = "vmess";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v2rayConfig.outbounds.AddRange(new[]
|
||||
@@ -274,7 +275,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
case "ws":
|
||||
var wsSettings = new WsSettings
|
||||
{
|
||||
headers = !string.IsNullOrWhiteSpace(server.Host) ? new Headers {Host = server.Host} : null,
|
||||
headers = !string.IsNullOrWhiteSpace(server.Host) ? new Headers { Host = server.Host } : null,
|
||||
path = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray.Utils;
|
||||
|
||||
@@ -10,9 +11,9 @@ namespace Netch.Servers.V2ray
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "xray.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"started"};
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "started" };
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"config file not readable", "failed to"};
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "config file not readable", "failed to" };
|
||||
|
||||
public override string Name { get; } = "Xray";
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.V2ray
|
||||
{
|
||||
@@ -13,7 +13,7 @@ namespace Netch.Servers.V2ray
|
||||
public static IEnumerable<Server> ParseVUri(string text)
|
||||
{
|
||||
var scheme = ShareLink.GetUriScheme(text).ToLower();
|
||||
var server = scheme switch {"vmess" => new VMess.VMess(), "vless" => new VLESS.VLESS(), _ => throw new ArgumentOutOfRangeException()};
|
||||
var server = scheme switch { "vmess" => new VMess.VMess(), "vless" => new VLESS.VLESS(), _ => throw new ArgumentOutOfRangeException() };
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
server.Remark = Uri.UnescapeDataString(text.Split('#')[1]);
|
||||
@@ -25,7 +25,7 @@ namespace Netch.Servers.V2ray
|
||||
var parameter = HttpUtility.ParseQueryString(text.Split('?')[1]);
|
||||
text = text.Substring(0, text.IndexOf("?", StringComparison.Ordinal));
|
||||
server.TransferProtocol = parameter.Get("type") ?? "tcp";
|
||||
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch {"vless" => "none", _ => "auto"};
|
||||
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch { "vless" => "none", _ => "auto" };
|
||||
switch (server.TransferProtocol)
|
||||
{
|
||||
case "tcp":
|
||||
@@ -54,7 +54,7 @@ namespace Netch.Servers.V2ray
|
||||
{
|
||||
server.Host = parameter.Get("sni") ?? "";
|
||||
if (server.TLSSecureType == "xtls")
|
||||
((VLESS.VLESS) server).Flow = parameter.Get("flow") ?? "";
|
||||
((VLESS.VLESS)server).Flow = parameter.Get("flow") ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,13 +67,13 @@ namespace Netch.Servers.V2ray
|
||||
server.Hostname = match.Groups["server"].Value;
|
||||
server.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
return new[] {server};
|
||||
return new[] { server };
|
||||
}
|
||||
|
||||
public static string GetVShareLink(Server s, string scheme = "vmess")
|
||||
{
|
||||
// https://github.com/XTLS/Xray-core/issues/91
|
||||
var server = (VMess.VMess) s;
|
||||
var server = (VMess.VMess)s;
|
||||
var parameter = new Dictionary<string, string>();
|
||||
// protocol-specific fields
|
||||
parameter.Add("type", server.TransferProtocol);
|
||||
@@ -127,7 +127,7 @@ namespace Netch.Servers.V2ray
|
||||
|
||||
if (server.TLSSecureType == "xtls")
|
||||
{
|
||||
var flow = ((VLESS.VLESS) server).Flow;
|
||||
var flow = ((VLESS.VLESS)server).Flow;
|
||||
if (!flow.IsNullOrWhiteSpace())
|
||||
parameter.Add("flow", flow!.Replace("-udp443", ""));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Servers.VMess;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.VLESS
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Forms;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.VLESS.VLESSForm
|
||||
{
|
||||
@@ -30,8 +30,8 @@ namespace Netch.Servers.VLESS.VLESSForm
|
||||
CreateTextBox("QUICSecret", "QUIC Secret", s => true, s => server.QUICSecret = s, server.QUICSecret);
|
||||
CreateComboBox("UseMux",
|
||||
"Use Mux",
|
||||
new List<string> {"", "true", "false"},
|
||||
s => server.UseMux = s switch {"" => null, "true" => true, "false" => false, _ => null},
|
||||
new List<string> { "", "true", "false" },
|
||||
s => server.UseMux = s switch { "" => null, "true" => true, "false" => false, _ => null },
|
||||
server.UseMux?.ToString().ToLower() ?? "");
|
||||
|
||||
CreateComboBox("TLSSecure", "TLS Secure", VLESSGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
|
||||
@@ -16,13 +16,13 @@ namespace Netch.Servers.VLESS
|
||||
|
||||
public string ShortName { get; } = "VL";
|
||||
|
||||
public string[] UriScheme { get; } = {"vless"};
|
||||
public string[] UriScheme { get; } = { "vless" };
|
||||
|
||||
public Type ServerType { get; } = typeof(VLESS);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new VLESSForm.VLESSForm((VLESS) s).ShowDialog();
|
||||
new VLESSForm.VLESSForm((VLESS)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Forms;
|
||||
using Netch.Forms;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.VMess.Form
|
||||
{
|
||||
@@ -25,8 +25,8 @@ namespace Netch.Servers.VMess.Form
|
||||
CreateTextBox("QUICSecret", "QUIC Secret", s => true, s => server.QUICSecret = s, server.QUICSecret);
|
||||
CreateComboBox("UseMux",
|
||||
"Use Mux",
|
||||
new List<string> {"", "true", "false"},
|
||||
s => server.UseMux = s switch {"" => null, "true" => true, "false" => false, _ => null},
|
||||
new List<string> { "", "true", "false" },
|
||||
s => server.UseMux = s switch { "" => null, "true" => true, "false" => false, _ => null },
|
||||
server.UseMux?.ToString().ToLower() ?? "");
|
||||
|
||||
CreateComboBox("TLSSecure", "TLS Secure", VMessGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.VMess
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
using Netch.Servers.V2ray.Models;
|
||||
@@ -22,13 +22,13 @@ namespace Netch.Servers.VMess
|
||||
|
||||
public string ShortName { get; } = "V2";
|
||||
|
||||
public string[] UriScheme { get; } = {"vmess"};
|
||||
public string[] UriScheme { get; } = { "vmess" };
|
||||
|
||||
public Type ServerType { get; } = typeof(VMess);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new VMessForm((VMess) s).ShowDialog();
|
||||
new VMessForm((VMess)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -40,22 +40,22 @@ namespace Netch.Servers.VMess
|
||||
{
|
||||
if (Global.Settings.V2RayConfig.V2rayNShareLink)
|
||||
{
|
||||
var server = (VMess) s;
|
||||
var server = (VMess)s;
|
||||
|
||||
var vmessJson = JsonSerializer.Serialize(new V2rayNSharing
|
||||
{
|
||||
v = 2,
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port,
|
||||
id = server.UserID,
|
||||
aid = server.AlterID,
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecureType
|
||||
},
|
||||
{
|
||||
v = 2,
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port,
|
||||
id = server.UserID,
|
||||
aid = server.AlterID,
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecureType
|
||||
},
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
@@ -87,7 +87,7 @@ namespace Netch.Servers.VMess
|
||||
}
|
||||
|
||||
V2rayNSharing vmess = JsonSerializer.Deserialize<V2rayNSharing>(s,
|
||||
new JsonSerializerOptions {NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString})!;
|
||||
new JsonSerializerOptions { NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString })!;
|
||||
|
||||
data.Remark = vmess.ps;
|
||||
data.Hostname = vmess.add;
|
||||
@@ -114,7 +114,7 @@ namespace Netch.Servers.VMess
|
||||
data.TLSSecureType = vmess.tls;
|
||||
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
|
||||
|
||||
return new[] {data};
|
||||
return new[] { data };
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
|
||||
@@ -6,12 +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>
|
||||
@@ -92,9 +93,9 @@ namespace Netch.Updater
|
||||
|
||||
#region Apply Update
|
||||
|
||||
private static readonly ImmutableArray<string> KeepDirectories = new List<string> {"data", "mode\\Custom", "logging"}.ToImmutableArray();
|
||||
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
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Diagnostics.Tracing.Parsers;
|
||||
using Microsoft.Diagnostics.Tracing.Parsers;
|
||||
using Microsoft.Diagnostics.Tracing.Session;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -14,7 +14,7 @@ namespace Netch.Utils
|
||||
public static ulong received;
|
||||
public static TraceEventSession? tSession;
|
||||
|
||||
private static readonly string[] Suffix = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
|
||||
private static readonly string[] Suffix = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };
|
||||
|
||||
/// <summary>
|
||||
/// 计算流量
|
||||
@@ -98,7 +98,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (processList.Contains(data.ProcessID))
|
||||
lock (counterLock)
|
||||
received += (ulong) data.size;
|
||||
received += (ulong)data.size;
|
||||
|
||||
// Debug.WriteLine($"TcpIpRecv: {ToByteSize(data.size)}");
|
||||
};
|
||||
@@ -107,7 +107,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (processList.Contains(data.ProcessID))
|
||||
lock (counterLock)
|
||||
received += (ulong) data.size;
|
||||
received += (ulong)data.size;
|
||||
|
||||
// Debug.WriteLine($"UdpIpRecv: {ToByteSize(data.size)}");
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using Netch.Models;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -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)
|
||||
|
||||
@@ -2,6 +2,8 @@ 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;
|
||||
@@ -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:
|
||||
{
|
||||
Socks5 => true,
|
||||
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS => true,
|
||||
_ => false
|
||||
};
|
||||
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()
|
||||
@@ -33,12 +33,12 @@ namespace Netch.Utils
|
||||
if (port == 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
var row = GetTcpTable2().Where(r => ntohs((ushort) r.dwLocalPort) == port).Where(r => r.dwOwningPid is not (0 or 4));
|
||||
var row = GetTcpTable2().Where(r => ntohs((ushort)r.dwLocalPort) == port).Where(r => r.dwOwningPid is not (0 or 4));
|
||||
|
||||
return row.Select(r => Process.GetProcessById((int) r.dwOwningPid));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Netch.Utils
|
||||
var random = new Random();
|
||||
for (ushort i = 0; i < 55535; i++)
|
||||
{
|
||||
var p = (ushort) random.Next(10000, 65535);
|
||||
var p = (ushort)random.Next(10000, 65535);
|
||||
try
|
||||
{
|
||||
CheckPort(p, portType);
|
||||
|
||||
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,7 +1,7 @@
|
||||
using System;
|
||||
using Netch.Models;
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -16,7 +16,7 @@ namespace Netch.Utils
|
||||
try
|
||||
{
|
||||
var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!);
|
||||
return (Server) JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
|
||||
return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -2,10 +2,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Range = Netch.Models.Range;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -17,7 +18,7 @@ namespace Netch.Utils
|
||||
.GetExportedTypes()
|
||||
.Where(type => type.GetInterfaces().Contains(typeof(IServerUtil)));
|
||||
|
||||
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil) Activator.CreateInstance(t)!).OrderBy(util => util.Priority);
|
||||
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).OrderBy(util => util.Priority);
|
||||
}
|
||||
|
||||
public static Type GetTypeByTypeName(string typeName)
|
||||
@@ -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()
|
||||
{
|
||||
@@ -57,7 +58,7 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static int Interval => (int) (Timer.Interval / 1000);
|
||||
public static int Interval => (int)(Timer.Interval / 1000);
|
||||
|
||||
private static bool ValueIsEnabled(int value)
|
||||
{
|
||||
@@ -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;
|
||||
Parallel.ForEach(Global.Settings.Server, new ParallelOptions { MaxDegreeOfParallelism = 16 }, server => { server.Test(); });
|
||||
TestDelayFinished?.Invoke(null, new EventArgs());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(TestAllLock);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateInterval()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Shadowsocks.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Shadowsocks.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -122,7 +122,7 @@ namespace Netch.Utils
|
||||
return JsonSerializer.Deserialize<Server>(text,
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
Converters = {new ServerConverterWithTypeDiscriminator()}
|
||||
Converters = { new ServerConverterWithTypeDiscriminator() }
|
||||
})!;
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Netch.Utils
|
||||
|
||||
private static string RemoveEmoji(string text)
|
||||
{
|
||||
byte[] emojiBytes = {240, 159};
|
||||
byte[] emojiBytes = { 240, 159 };
|
||||
var remark = Encoding.UTF8.GetBytes(text);
|
||||
var startIndex = 0;
|
||||
while (remark.Length > startIndex + 1 && remark[startIndex] == emojiBytes[0] && remark[startIndex + 1] == emojiBytes[1])
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Netch.Utils
|
||||
var sb = new StringBuilder();
|
||||
foreach (var t in value)
|
||||
{
|
||||
var escapeCharacters = new[] {'\\', '*', '+', '?', '|', '{', '}', '[', ']', '(', ')', '^', '$', '.'};
|
||||
var escapeCharacters = new[] { '\\', '*', '+', '?', '|', '{', '}', '[', ']', '(', ')', '^', '$', '.' };
|
||||
if (escapeCharacters.Any(s => s == t))
|
||||
sb.Append('\\');
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Netch.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
|
||||
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;
|
||||
|
||||
@@ -219,8 +222,8 @@ namespace Netch.Utils
|
||||
{
|
||||
case TextBox _:
|
||||
case ComboBox _:
|
||||
if (((Control) component).ForeColor != color)
|
||||
((Control) component).ForeColor = color;
|
||||
if (((Control)component).ForeColor != color)
|
||||
((Control)component).ForeColor = color;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user