mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
193 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 | ||
|
|
1099b2c6e6 | ||
|
|
295c5958fd | ||
|
|
9a3a85078e | ||
|
|
c14fa70a08 | ||
|
|
ebcde8cf55 | ||
|
|
5fca9c55fe | ||
|
|
9f105425ab | ||
|
|
4a3d6c49d0 | ||
|
|
fa23561827 | ||
|
|
96b8c42918 | ||
|
|
9b41ea99e5 | ||
|
|
6099891280 | ||
|
|
b8676df2ab | ||
|
|
5970e30974 | ||
|
|
37455bb89e | ||
|
|
9437ec7e5d | ||
|
|
93faf8a82e | ||
|
|
8a5c0dcd1d | ||
|
|
559f1dc8a9 | ||
|
|
d0c71698aa | ||
|
|
98bf6c3c9b | ||
|
|
8a6970cc26 | ||
|
|
c0b1ae193b | ||
|
|
f7d8af6592 | ||
|
|
7d7643ad77 | ||
|
|
15f9c6d4f5 | ||
|
|
732066ccf8 | ||
|
|
483dccc5d2 | ||
|
|
42b609b597 | ||
|
|
7ab89b67c5 | ||
|
|
a33c2c3757 | ||
|
|
268bdb7730 | ||
|
|
ed459ec8d6 | ||
|
|
ddd1ca5fac | ||
|
|
7c54c1f570 | ||
|
|
ed56d51c4d | ||
|
|
c669097aa5 | ||
|
|
5d74321771 | ||
|
|
093fe6404b | ||
|
|
2760b3c7bd | ||
|
|
ba17366094 | ||
|
|
6c668684e9 | ||
|
|
8d6e4bdd96 | ||
|
|
5522245ce0 | ||
|
|
f518fd6867 | ||
|
|
e0120e7de0 | ||
|
|
3565251b4d | ||
|
|
4a50ebd421 | ||
|
|
4e03793ceb | ||
|
|
23399b872d | ||
|
|
b553ddbb71 | ||
|
|
090e487733 | ||
|
|
cada4c997e | ||
|
|
8746125dda | ||
|
|
d09b5adc33 | ||
|
|
54c1fb5578 | ||
|
|
f07413c882 | ||
|
|
5b2b6c9f96 | ||
|
|
4c4ad72d1d | ||
|
|
830f3b3b60 | ||
|
|
777657e810 | ||
|
|
2413aabb15 | ||
|
|
6ccb99d1d8 | ||
|
|
ac0266a478 | ||
|
|
d701a8c950 | ||
|
|
934443556c | ||
|
|
a69252819c | ||
|
|
f90773aa84 | ||
|
|
246f52e54e | ||
|
|
a5f6b4a2c0 | ||
|
|
66d7cededd | ||
|
|
8254482799 | ||
|
|
b215b2caa8 | ||
|
|
5f9dbb0994 | ||
|
|
3cbd5af9a3 | ||
|
|
2ab693facf | ||
|
|
664b1a7e6c | ||
|
|
ad1575b3c7 | ||
|
|
62b78d1b1d | ||
|
|
dd3ce126e3 | ||
|
|
a295cf6250 | ||
|
|
a507df5f30 | ||
|
|
0a7b405f1b | ||
|
|
c61da9b918 | ||
|
|
9bf3490cf9 | ||
|
|
c505e2abbb | ||
|
|
5fc7c460aa | ||
|
|
c79f62334c | ||
|
|
2dc4308427 | ||
|
|
c3c534eb92 | ||
|
|
dbef41d8a4 | ||
|
|
e3d6a62e81 | ||
|
|
415c7705ac | ||
|
|
4ab844e31c | ||
|
|
f4759d2f94 | ||
|
|
a080de6ca4 | ||
|
|
f8148cb730 | ||
|
|
b092b6a4d4 |
@@ -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
vendored
32
.github/ISSUE_TEMPLATE/bug_report.md
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.
|
||||
51
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
labels: bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
placeholder: |
|
||||
1. Open Netch
|
||||
2. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: captcha
|
||||
attributes:
|
||||
label: CAPTCHA
|
||||
description: Please confirm the options below.
|
||||
options:
|
||||
- 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:
|
||||
label: Log
|
||||
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 x64 Professional Workstation 20H2 19042.928]
|
||||
- Netch Version: [e.g. 1.0.0]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
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
vendored
29
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md
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 位]
|
||||
|
||||
**额外信息**
|
||||
43
.github/ISSUE_TEMPLATE/bug_report.zh-CN.yml
vendored
Normal file
43
.github/ISSUE_TEMPLATE/bug_report.zh-CN.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: 错误报告
|
||||
description: 创建错误报告以帮助我们改进
|
||||
labels: bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: 错误描述
|
||||
description: 对错误的清晰简洁描述
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: 复现步骤
|
||||
placeholder: |
|
||||
1. 打开 Netch 软件
|
||||
2. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: 日志
|
||||
description: 强烈建议附上任何在 `logging` 文件夹下面的日志
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: 操作环境
|
||||
render: txt
|
||||
placeholder: |
|
||||
操作系统:[Windows 10 x64 Professional Workstation 20H2 19042.928]
|
||||
软件版本:[1.0.0]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
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
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md
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.
|
||||
11
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for this project
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the feature you want
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
15
.github/ISSUE_TEMPLATE/feature_request.zh-CN.md
vendored
15
.github/ISSUE_TEMPLATE/feature_request.zh-CN.md
vendored
@@ -1,15 +0,0 @@
|
||||
---
|
||||
name: '功能请求'
|
||||
about: '建议这个项目的想法'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
|
||||
|
||||
**功能描述**
|
||||
简明扼要地描述需要的功能
|
||||
|
||||
**额外信息**
|
||||
11
.github/ISSUE_TEMPLATE/feature_request.zh-CN.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/feature_request.zh-CN.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
name: 功能请求
|
||||
description: 建议这个项目的想法
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
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
|
||||
|
||||
27
.github/workflows/build.yml
vendored
Normal file
27
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Netch Build CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
run: |
|
||||
.\build.ps1 -Configuration Release -OutputPath release
|
||||
|
||||
- name: Upload
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: release
|
||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: Netch CI
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
dependabot/**
|
||||
pull_request:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Build Solution
|
||||
shell: pwsh
|
||||
run: .\BUILD.ps1
|
||||
|
||||
- name: Upload Artifact
|
||||
continue-on-error: true
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: Netch\bin\x64\Release
|
||||
36
.github/workflows/release.yml
vendored
36
.github/workflows/release.yml
vendored
@@ -1,46 +1,46 @@
|
||||
name: Netch Release
|
||||
name: Netch Release CI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*'
|
||||
- '*.*.*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Setup MSBuild
|
||||
- name: MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build Solution
|
||||
shell: pwsh
|
||||
run: .\BUILD.ps1
|
||||
|
||||
- name: Package
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Path C:\builtfiles -Force > $null
|
||||
7z a -mx9 C:\builtfiles\Netch.7z .\Netch\bin\x64\Release\
|
||||
7z rn C:\builtfiles\Netch.7z Release Netch
|
||||
echo "Netch_SHA256=$(.\GetSHA256.ps1 C:\builtfiles\Netch.7z)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
echo "Netch_EXE_SHA256=$(.\GetSHA256.ps1 Netch\bin\x64\Release\Netch.exe)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
.\build.ps1 -Configuration Release -OutputPath release
|
||||
|
||||
- name: Package
|
||||
shell: pwsh
|
||||
run: |
|
||||
7z a -mx9 Netch.7z release
|
||||
7z rn Netch.7z release Netch
|
||||
|
||||
echo "NETCH_SHA256=$(.\sha256.ps1 Netch.7z)" | Out-File -Append -Encoding UTF8 -FilePath $Env:GITHUB_ENV
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
prerelease: ${{ contains(github.ref, '-') }}
|
||||
draft: false
|
||||
files: |
|
||||
C:\builtfiles\Netch.7z
|
||||
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
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -1,9 +0,0 @@
|
||||
[submodule "binaries"]
|
||||
path = binaries
|
||||
url = https://github.com/NetchX/NetchBinaries
|
||||
[submodule "modes"]
|
||||
path = modes
|
||||
url = https://github.com/NetchX/NetchMode
|
||||
[submodule "translations"]
|
||||
path = translations
|
||||
url = https://github.com/NetchX/NetchTranslation
|
||||
12
BUILD.ps1
12
BUILD.ps1
@@ -1,12 +0,0 @@
|
||||
Write-Host 'Building'
|
||||
|
||||
msbuild -v:n /p:Configuration="Release" `
|
||||
/p:Platform="x64" `
|
||||
/p:TargetFramework=net48 `
|
||||
/p:SolutionDir="$pwd\" `
|
||||
/restore `
|
||||
Netch\Netch.csproj
|
||||
|
||||
if ($LASTEXITCODE) { exit $LASTEXITCODE }
|
||||
|
||||
Write-Host 'Build done'
|
||||
21
CLEAN.ps1
21
CLEAN.ps1
@@ -1,21 +0,0 @@
|
||||
if (Test-Path Netch\bin)
|
||||
{
|
||||
Remove-Item -Recurse -Force Netch\bin
|
||||
}
|
||||
|
||||
if (Test-Path Netch\obj)
|
||||
{
|
||||
Remove-Item -Recurse -Force Netch\obj
|
||||
}
|
||||
|
||||
if (Test-Path NetchLib\bin)
|
||||
{
|
||||
Remove-Item -Recurse -Force NetchLib\bin
|
||||
}
|
||||
|
||||
if (Test-Path NetchLib\obj)
|
||||
{
|
||||
Remove-Item -Recurse -Force NetchLib\obj
|
||||
}
|
||||
|
||||
exit 0
|
||||
53
GSF.md
53
GSF.md
@@ -1,53 +0,0 @@
|
||||
```json
|
||||
{
|
||||
"Type": "",
|
||||
"Rate": 1,
|
||||
"Remark": "",
|
||||
"Hostname": "",
|
||||
"Port": 0,
|
||||
"Username": "",
|
||||
"Password": "",
|
||||
"EncryptMethod": "",
|
||||
"Plugin": "",
|
||||
"PluginOption": "",
|
||||
"Protocol": "",
|
||||
"ProtocolParam": "",
|
||||
"OBFS": "",
|
||||
"OBFSParam": "",
|
||||
"UserID": "",
|
||||
"AlterID": 0,
|
||||
"TransferProtocol": "",
|
||||
"FakeType": "",
|
||||
"Host": "",
|
||||
"Path": "",
|
||||
"QUICSecure": "",
|
||||
"QUICSecret": "",
|
||||
"TLSSecure": false
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
| :- | :- |
|
||||
| Type | 代理类型(HTTP、HTTPS、Socks5、SS、SSR、VMess) |
|
||||
| Rate | 倍率 |
|
||||
| Remark | 备注 |
|
||||
| Hostname | 主机名 |
|
||||
| Port | 端口 |
|
||||
| Username | 账号(HTTP、HTTPS、Socks5) |
|
||||
| Password | 密码(HTTP、HTTPS、Socks5、SS、SSR) |
|
||||
| UserID | 用户 ID(VMess) |
|
||||
| AlterID | 额外 ID(VMess) |
|
||||
| EncryptMethod | 加密方式(SS、SSR、VMess) |
|
||||
| Plugin | 插件(SS) |
|
||||
| PluginOption | 插件参数(SS) |
|
||||
| Protocol | 协议(SSR) |
|
||||
| ProtocolParam | 协议参数(SSR) |
|
||||
| OBFS | 混淆(SSR) |
|
||||
| OBFSParam | 混淆参数(SSR) |
|
||||
| TransferProtcol | 传输协议(VMess) |
|
||||
| FakeType | 伪装类型(VMess) |
|
||||
| Host | 伪装域名(VMess) |
|
||||
| Path | 传输路径(VMess) |
|
||||
| QUICSecure | QUIC 加密方式(VMess) |
|
||||
| QUICSecret | QUIC 加密密钥(VMess) |
|
||||
| TLSSecure | TLS 底层传输安全(VMess) |
|
||||
@@ -1,6 +0,0 @@
|
||||
param([string]$file)
|
||||
$hash = [Security.Cryptography.HashAlgorithm]::Create( "SHA256" )
|
||||
$path = (Resolve-Path -Path $file).Path
|
||||
$stream = ([IO.StreamReader]$path).BaseStream
|
||||
-join ($hash.ComputeHash($stream) | ForEach-Object { "{0:x2}" -f $_ })
|
||||
$stream.Close()
|
||||
@@ -1,9 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
67
Netch.sln
67
Netch.sln
@@ -1,42 +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
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SearchComboBox", "SearchComboBox\SearchComboBox.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "UnitTest\UnitTest.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interop.nfapinet", "Interop.nfapinet\Interop.nfapinet.csproj", "{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}"
|
||||
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
|
||||
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Release|x64.Build.0 = Release|Any CPU
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|x64
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|x64
|
||||
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Release|x64.Build.0 = Release|Any CPU
|
||||
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
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<System.Windows.Forms.ApplicationConfigurationSection>
|
||||
<add key="DpiAwareness" value="PerMonitorV2" />
|
||||
</System.Windows.Forms.ApplicationConfigurationSection>
|
||||
</configuration>
|
||||
@@ -3,14 +3,11 @@
|
||||
public static class Constants
|
||||
{
|
||||
public const string EOF = "\r\n";
|
||||
public const string UserACL = "data\\user.acl";
|
||||
public const string BuiltinACL = "bin\\default.acl";
|
||||
|
||||
public static class Parameter
|
||||
{
|
||||
public const string Show = "-show";
|
||||
public const string ForceUpdate = "-forceUpdate";
|
||||
public const string Console = "-console";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Netch.Interfaces;
|
||||
using static Netch.Interops.AioDNS;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -9,9 +9,11 @@ namespace Netch.Controllers
|
||||
{
|
||||
public string Name { get; } = "DNS Service";
|
||||
|
||||
private const string RulePath = "bin\\aiodns.conf";
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
aiodns_free();
|
||||
Free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -20,38 +22,14 @@ namespace Netch.Controllers
|
||||
/// <returns></returns>
|
||||
public void Start()
|
||||
{
|
||||
aiodns_dial((int) NameList.TYPE_REST, null);
|
||||
aiodns_dial((int) NameList.TYPE_ADDR, Encoding.UTF8.GetBytes($"{Global.Settings.LocalAddress}:53"));
|
||||
aiodns_dial((int) NameList.TYPE_LIST, Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)));
|
||||
aiodns_dial((int) NameList.TYPE_CDNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"));
|
||||
aiodns_dial((int) NameList.TYPE_ODNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"));
|
||||
aiodns_dial((int) NameList.TYPE_METH, Encoding.UTF8.GetBytes(Global.Settings.AioDNS.Protocol));
|
||||
Dial(NameList.TYPE_REST, "");
|
||||
Dial(NameList.TYPE_ADDR, $"{Global.Settings.LocalAddress}:{Global.Settings.AioDNS.ListenPort}");
|
||||
Dial(NameList.TYPE_LIST, Path.GetFullPath(RulePath));
|
||||
Dial(NameList.TYPE_CDNS, $"{Global.Settings.AioDNS.ChinaDNS}");
|
||||
Dial(NameList.TYPE_ODNS, $"{Global.Settings.AioDNS.OtherDNS}");
|
||||
|
||||
if (!aiodns_init())
|
||||
if (!Init())
|
||||
throw new Exception("AioDNS start failed");
|
||||
}
|
||||
|
||||
#region NativeMethods
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_dial(int name, byte[]? value);
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_init();
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void aiodns_free();
|
||||
|
||||
private enum NameList
|
||||
{
|
||||
TYPE_REST,
|
||||
TYPE_ADDR,
|
||||
TYPE_LIST,
|
||||
TYPE_CDNS,
|
||||
TYPE_ODNS,
|
||||
TYPE_METH
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Logging.Error($"停止 {MainFile} 错误:\n" + e);
|
||||
Global.Logger.Error($"停止 {MainFile} 错误:\n" + e);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -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
|
||||
@@ -268,7 +275,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logging.Warning($"写入 {Name} 日志错误:\n" + exception.Message);
|
||||
Global.Logger.Warning($"写入 {Name} 日志错误:\n" + exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using WindowsProxy;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Servers.Trojan;
|
||||
using Netch.Utils;
|
||||
using Netch.Utils.HttpProxyHandler;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class HTTPController : IModeController
|
||||
{
|
||||
public readonly PrivoxyController PrivoxyController = new();
|
||||
|
||||
private ProxyStatus? _oldState;
|
||||
|
||||
public string Name { get; } = "HTTP";
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
PrivoxyController.Start(MainController.Server!);
|
||||
string? pacUrl = null;
|
||||
|
||||
if (MainController.Server is Socks5 or Trojan && mode.BypassChina || (Global.Settings.AlwaysStartPACServer ?? false))
|
||||
{
|
||||
try
|
||||
{
|
||||
PortHelper.CheckPort(Global.Settings.Pac_Port);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Global.Settings.Pac_Port = PortHelper.GetAvailablePort();
|
||||
}
|
||||
|
||||
pacUrl = PACServerHandle.InitPACServer();
|
||||
}
|
||||
|
||||
if (mode.Type is 3)
|
||||
{
|
||||
using var service = new ProxyService();
|
||||
_oldState = service.Query();
|
||||
|
||||
if (pacUrl != null)
|
||||
{
|
||||
service.AutoConfigUrl = pacUrl;
|
||||
service.Pac();
|
||||
}
|
||||
else
|
||||
{
|
||||
service.Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
service.Bypass = string.Join(";", ProxyService.LanIp);
|
||||
|
||||
service.Global();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(PrivoxyController.Stop),
|
||||
Task.Run(() =>
|
||||
{
|
||||
PACServerHandle.Stop();
|
||||
|
||||
if (_oldState != null)
|
||||
{
|
||||
using var service = new ProxyService();
|
||||
if (_oldState.IsProxy && _oldState.ProxyServer == service.Query().ProxyServer ||
|
||||
_oldState.IsAutoProxyUrl && _oldState.AutoConfigUrl!.StartsWith(PACServerHandle.PacPrefix))
|
||||
{
|
||||
service.Direct();
|
||||
return;
|
||||
}
|
||||
|
||||
service.Set(_oldState);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
@@ -55,20 +55,17 @@ namespace Netch.Controllers
|
||||
|
||||
public static void Start(Server server, Mode mode)
|
||||
{
|
||||
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
Global.Logger.Info($"启动主控制器: {server.Type} [{(int)mode.Type}]{mode.Remark}");
|
||||
Server = server;
|
||||
Mode = mode;
|
||||
|
||||
if (server is Socks5 && mode.Type == 4)
|
||||
throw new MessageException("Already Socks5 Server");
|
||||
|
||||
// 刷新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
|
||||
@@ -93,8 +90,8 @@ namespace Netch.Controllers
|
||||
case MessageException:
|
||||
throw;
|
||||
default:
|
||||
Logging.Error(e.ToString());
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
Global.Logger.Error(e.ToString());
|
||||
Global.Logger.ShowLog();
|
||||
throw new MessageException($"未处理异常\n{e.Message}");
|
||||
}
|
||||
}
|
||||
@@ -125,11 +122,8 @@ namespace Netch.Controllers
|
||||
{
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName);
|
||||
|
||||
if (ModeController == null)
|
||||
return;
|
||||
|
||||
if (port != null)
|
||||
TryReleaseTcpPort((ushort) port, portName);
|
||||
TryReleaseTcpPort((ushort)port, portName);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
|
||||
@@ -165,8 +159,8 @@ namespace Netch.Controllers
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
Global.Logger.Error(e.ToString());
|
||||
Global.Logger.ShowLog();
|
||||
}
|
||||
|
||||
ModeController = null;
|
||||
@@ -193,16 +187,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
|
||||
{
|
||||
string fileName;
|
||||
try
|
||||
{
|
||||
fileName = p.MainModule!.FileName;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Warning(e.ToString());
|
||||
var fileName = p.MainModule?.FileName;
|
||||
if (fileName == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileName.StartsWith(Global.NetchDir))
|
||||
{
|
||||
@@ -218,15 +205,4 @@ namespace Netch.Controllers
|
||||
PortCheck(port, portName, PortType.TCP);
|
||||
}
|
||||
}
|
||||
|
||||
public class MessageException : Exception
|
||||
{
|
||||
public MessageException()
|
||||
{
|
||||
}
|
||||
|
||||
public MessageException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using nfapinet;
|
||||
using static Netch.Interops.Redirector;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -26,29 +26,30 @@ namespace Netch.Controllers
|
||||
{
|
||||
CheckDriver();
|
||||
|
||||
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
|
||||
Dial(NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
Dial(NameList.TYPE_FILTERICMP, "true");
|
||||
var p = PortHelper.GetAvailablePort();
|
||||
Dial(NameList.TYPE_TCPLISN, p.ToString());
|
||||
Dial(NameList.TYPE_UDPLISN, p.ToString());
|
||||
|
||||
// Server
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, (Global.Settings.ProcessProxyProtocol != PortType.TCP).ToString().ToLower());
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, (Global.Settings.ProcessProxyProtocol != PortType.UDP).ToString().ToLower());
|
||||
dial_Server(Global.Settings.ProcessProxyProtocol);
|
||||
Dial(NameList.TYPE_FILTERUDP, (Global.Settings.Redirector.ProxyProtocol != PortType.TCP).ToString().ToLower());
|
||||
Dial(NameList.TYPE_FILTERTCP, (Global.Settings.Redirector.ProxyProtocol != PortType.UDP).ToString().ToLower());
|
||||
dial_Server(Global.Settings.Redirector.ProxyProtocol);
|
||||
|
||||
// Mode Rule
|
||||
dial_Name(mode);
|
||||
|
||||
// Features
|
||||
aio_dial((int) NameList.TYPE_REDIRCTOR_DNS, Global.Settings.RedirectDNS ? Global.Settings.RedirectDNSAddr : "");
|
||||
aio_dial((int) NameList.TYPE_REDIRCTOR_ICMP, Global.Settings.RedirectICMP ? Global.Settings.RedirectICMPAddr : "");
|
||||
aio_dial((int) NameList.TYPE_FILTERCHILDPROC, Global.Settings.ChildProcessHandle.ToString().ToLower());
|
||||
Dial(NameList.TYPE_DNSHOST, Global.Settings.Redirector.DNSHijack ? Global.Settings.Redirector.DNSHijackHost : "");
|
||||
|
||||
if (!aio_init())
|
||||
if (!Init())
|
||||
throw new MessageException("Redirector Start failed, run Netch with \"-console\" argument");
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
aio_free();
|
||||
Free();
|
||||
}
|
||||
|
||||
#region CheckRule
|
||||
@@ -63,14 +64,14 @@ namespace Netch.Controllers
|
||||
try
|
||||
{
|
||||
if (r.StartsWith("!"))
|
||||
return aio_dial((int) NameList.TYPE_ADDNAME, r.Substring(1));
|
||||
return Dial(NameList.TYPE_ADDNAME, r.Substring(1));
|
||||
|
||||
return aio_dial((int) NameList.TYPE_ADDNAME, r);
|
||||
return Dial(NameList.TYPE_ADDNAME, r);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (clear)
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ namespace Netch.Controllers
|
||||
public static bool CheckRules(IEnumerable<string> rules, out IEnumerable<string> results)
|
||||
{
|
||||
results = rules.Where(r => !CheckCppRegex(r, false));
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
return !results.Any();
|
||||
}
|
||||
|
||||
@@ -121,52 +122,52 @@ namespace Netch.Controllers
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
|
||||
aio_dial((int) NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
Dial(NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
Dial(NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
|
||||
Dial(NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
|
||||
Dial(NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
|
||||
Dial(NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
}
|
||||
else if (server is Shadowsocks shadowsocks && !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS)
|
||||
else if (server is Shadowsocks shadowsocks && !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, shadowsocks.Password);
|
||||
Dial(NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
|
||||
Dial(NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
|
||||
Dial(NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod);
|
||||
Dial(NameList.TYPE_TCPPASS + offset, shadowsocks.Password);
|
||||
}
|
||||
else
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"127.0.0.1:{controller.Socks5LocalPort()}");
|
||||
aio_dial((int) NameList.TYPE_TCPUSER + offset, string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
Dial(NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
Dial(NameList.TYPE_TCPHOST + offset, $"127.0.0.1:{controller.Socks5LocalPort()}");
|
||||
Dial(NameList.TYPE_TCPUSER + offset, string.Empty);
|
||||
Dial(NameList.TYPE_TCPPASS + offset, string.Empty);
|
||||
Dial(NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void dial_Name(Mode mode)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
var list = new List<string>();
|
||||
foreach (var s in mode.FullRule)
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
var invalidList = new List<string>();
|
||||
foreach (var s in mode.GetRules())
|
||||
{
|
||||
if (s.StartsWith("!"))
|
||||
{
|
||||
if (!aio_dial((int) NameList.TYPE_BYPNAME, s.Substring(1)))
|
||||
list.Add(s);
|
||||
if (!Dial(NameList.TYPE_BYPNAME, s.Substring(1)))
|
||||
invalidList.Add(s);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!aio_dial((int) NameList.TYPE_ADDNAME, s))
|
||||
list.Add(s);
|
||||
if (!Dial(NameList.TYPE_ADDNAME, s))
|
||||
invalidList.Add(s);
|
||||
}
|
||||
|
||||
if (list.Any())
|
||||
throw new MessageException(GenerateInvalidRulesMessage(list));
|
||||
if (invalidList.Any())
|
||||
throw new MessageException(GenerateInvalidRulesMessage(invalidList));
|
||||
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, @"NTT\.exe");
|
||||
aio_dial((int) NameList.TYPE_BYPNAME, "^" + Global.NetchDir.ToRegexString() + @"((?!NTT\.exe).)*$");
|
||||
Dial(NameList.TYPE_ADDNAME, @"NTT\.exe");
|
||||
Dial(NameList.TYPE_BYPNAME, "^" + Global.NetchDir.ToRegexString() + @"((?!NTT\.exe).)*$");
|
||||
}
|
||||
|
||||
#region DriverUtil
|
||||
@@ -176,8 +177,8 @@ namespace Netch.Controllers
|
||||
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
|
||||
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
|
||||
|
||||
Logging.Info("内置驱动版本: " + binFileVersion);
|
||||
Logging.Info("系统驱动版本: " + systemFileVersion);
|
||||
Global.Logger.Info("内置驱动版本: " + binFileVersion);
|
||||
Global.Logger.Info("系统驱动版本: " + systemFileVersion);
|
||||
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
@@ -207,7 +208,7 @@ namespace Netch.Controllers
|
||||
if (!reinstall)
|
||||
return;
|
||||
|
||||
Logging.Info("更新驱动");
|
||||
Global.Logger.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
InstallDriver();
|
||||
}
|
||||
@@ -216,9 +217,9 @@ namespace Netch.Controllers
|
||||
/// 安装 NF 驱动
|
||||
/// </summary>
|
||||
/// <returns>驱动是否安装成功</returns>
|
||||
public static void InstallDriver()
|
||||
private static void InstallDriver()
|
||||
{
|
||||
Logging.Info("安装 NF 驱动");
|
||||
Global.Logger.Info("安装 NF 驱动");
|
||||
|
||||
if (!File.Exists(BinDriver))
|
||||
throw new MessageException(i18N.Translate("builtin driver files missing, can't install NF driver"));
|
||||
@@ -229,7 +230,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("驱动复制失败\n" + e);
|
||||
Global.Logger.Error("驱动复制失败\n" + e);
|
||||
throw new MessageException($"Copy NF driver file failed\n{e.Message}");
|
||||
}
|
||||
|
||||
@@ -238,11 +239,11 @@ namespace Netch.Controllers
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result == NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Logging.Info("驱动安装成功");
|
||||
Global.Logger.Info("驱动安装成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error($"注册驱动失败,返回值:{result}");
|
||||
Global.Logger.Error($"注册驱动失败,返回值:{result}");
|
||||
throw new MessageException($"Register NF driver failed\n{result}");
|
||||
}
|
||||
}
|
||||
@@ -253,7 +254,7 @@ namespace Netch.Controllers
|
||||
/// <returns>是否成功卸载</returns>
|
||||
public static bool UninstallDriver()
|
||||
{
|
||||
Logging.Info("卸载 NF 驱动");
|
||||
Global.Logger.Info("卸载 NF 驱动");
|
||||
try
|
||||
{
|
||||
if (NFService.Status == ServiceControllerStatus.Running)
|
||||
@@ -277,61 +278,5 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region NativeMethods
|
||||
|
||||
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_init();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_free();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getUP();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getDL();
|
||||
|
||||
public enum NameList
|
||||
{
|
||||
//bool
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
TYPE_FILTERIP,
|
||||
TYPE_FILTERCHILDPROC, //子进程捕获
|
||||
|
||||
TYPE_TCPLISN,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
|
||||
TYPE_ADDNAME,
|
||||
TYPE_ADDFIP,
|
||||
|
||||
TYPE_BYPNAME,
|
||||
|
||||
TYPE_CLRNAME,
|
||||
TYPE_CLRFIP,
|
||||
|
||||
//str addr x.x.x.x only ipv4
|
||||
TYPE_REDIRCTOR_DNS,
|
||||
TYPE_REDIRCTOR_ICMP
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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,11 +36,11 @@ 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)
|
||||
{
|
||||
Logging.Warning($"写入 {Name} 日志错误:\n" + e.Message);
|
||||
Global.Logger.Warning($"写入 {Name} 日志错误:\n" + e.Message);
|
||||
}
|
||||
|
||||
if (output.IsNullOrWhiteSpace())
|
||||
@@ -86,7 +87,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"{Name} 控制器出错:\n" + e);
|
||||
Global.Logger.Error($"{Name} 控制器出错:\n" + e);
|
||||
try
|
||||
{
|
||||
Stop();
|
||||
|
||||
@@ -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,45 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class PrivoxyController : Guard, IController
|
||||
{
|
||||
public PrivoxyController()
|
||||
{
|
||||
RedirectStd = false;
|
||||
}
|
||||
|
||||
public override string MainFile { get; protected set; } = "Privoxy.exe";
|
||||
|
||||
public override string Name { get; } = "Privoxy";
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
public void Start(Server server)
|
||||
{
|
||||
var text = new StringBuilder(File.ReadAllText("bin\\default.conf"));
|
||||
|
||||
text.Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString());
|
||||
text.Replace("0.0.0.0", Global.Settings.LocalAddress); /* BIND_HOST */
|
||||
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
{
|
||||
text.Replace("/ 127.0.0.1", $"/ {server.AutoResolveHostname()}"); /* DEST_HOST */
|
||||
text.Replace("_DEST_PORT_", socks5.Port.ToString());
|
||||
}
|
||||
|
||||
text.Replace("_DEST_PORT_", Global.Settings.Socks5LocalPort.ToString());
|
||||
|
||||
|
||||
File.WriteAllText("data\\privoxy.conf", text.ToString());
|
||||
|
||||
StartInstanceAuto("..\\data\\privoxy.conf");
|
||||
}
|
||||
}
|
||||
}
|
||||
209
Netch/Controllers/TUNController.cs
Normal file
209
Netch/Controllers/TUNController.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
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 Netch.Interops;
|
||||
using static Netch.Interops.tun2socks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNController : IModeController
|
||||
{
|
||||
public string Name => "tun2socks";
|
||||
|
||||
private const string DummyDns = "6.6.6.6";
|
||||
|
||||
private readonly DNSController _aioDnsController = new();
|
||||
|
||||
private NetRoute _outbound;
|
||||
|
||||
private NetRoute _tun;
|
||||
|
||||
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, address.ToString());
|
||||
Dial(NameList.TYPE_BYPLIST, "disabled");
|
||||
|
||||
#region Server
|
||||
|
||||
Dial(NameList.TYPE_TCPREST, "");
|
||||
Dial(NameList.TYPE_TCPTYPE, "Socks5");
|
||||
|
||||
Dial(NameList.TYPE_UDPREST, "");
|
||||
Dial(NameList.TYPE_UDPTYPE, "Socks5");
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
Dial(NameList.TYPE_TCPHOST, $"{server.AutoResolveHostname()}:{server.Port}");
|
||||
|
||||
Dial(NameList.TYPE_UDPHOST, $"{server.AutoResolveHostname()}:{server.Port}");
|
||||
|
||||
if (socks5.Auth())
|
||||
{
|
||||
Dial(NameList.TYPE_TCPUSER, socks5.Username!);
|
||||
Dial(NameList.TYPE_TCPPASS, socks5.Password!);
|
||||
|
||||
Dial(NameList.TYPE_UDPUSER, socks5.Username!);
|
||||
Dial(NameList.TYPE_UDPPASS, socks5.Password!);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
|
||||
Dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DNS
|
||||
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
Dial(NameList.TYPE_DNSADDR, Global.Settings.TUNTAP.HijackDNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
|
||||
_aioDnsController.Start();
|
||||
Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (!Init())
|
||||
throw new MessageException("tun2socks start failed, reboot your system and start again.");
|
||||
|
||||
var tunIndex = (int)RouteHelper.ConvertLuidToIndex(tun_luid());
|
||||
_tun = NetRoute.TemplateBuilder(Global.Settings.TUNTAP.Gateway, tunIndex);
|
||||
|
||||
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
Global.Settings.TUNTAP.Address,
|
||||
(byte)Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
|
||||
(ulong)tunIndex);
|
||||
|
||||
SetupRouteTable(mode);
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
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)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Global.Logger.Info("Copy wintun.dll to System Directory");
|
||||
File.Copy(binDriver, sysDriver, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error(e.ToString());
|
||||
throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNTAPController : Guard, IModeController
|
||||
{
|
||||
private readonly List<string> _directIPs = new();
|
||||
|
||||
private readonly List<string> _proxyIPs = new();
|
||||
/// <summary>
|
||||
/// 服务器 IP 地址
|
||||
/// </summary>
|
||||
private IPAddress _serverAddresses = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 本地 DNS 服务控制器
|
||||
/// </summary>
|
||||
public DNSController DNSController = new();
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"Running"};
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"failed", "invalid vconfig file"};
|
||||
|
||||
public override string MainFile { get; protected set; } = "tun2socks.exe";
|
||||
|
||||
protected override Encoding InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
public override string Name { get; } = "tun2socks";
|
||||
|
||||
private readonly OutboundAdapter _outbound = new();
|
||||
private TapAdapter _tap = null!;
|
||||
|
||||
public void Start(in Mode mode)
|
||||
{
|
||||
var server = MainController.Server!;
|
||||
_serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start
|
||||
|
||||
if (TUNTAP.GetComponentID() == null)
|
||||
TUNTAP.AddTap();
|
||||
|
||||
_tap = new TapAdapter();
|
||||
|
||||
List<string> dns;
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
dns = Global.Settings.TUNTAP.DNS.Any() ? Global.Settings.TUNTAP.DNS : Global.Settings.TUNTAP.DNS = new List<string> {"1.1.1.1"};
|
||||
}
|
||||
else
|
||||
{
|
||||
MainController.PortCheck(53, "DNS");
|
||||
DNSController.Start();
|
||||
dns = new List<string> {"127.0.0.1"};
|
||||
}
|
||||
|
||||
var parameter = new Tun2SocksParameter
|
||||
{
|
||||
tunAddr = Global.Settings.TUNTAP.Address,
|
||||
tunMask = Global.Settings.TUNTAP.Netmask,
|
||||
tunGw = Global.Settings.TUNTAP.Gateway,
|
||||
tunDns = DnsUtils.Join(dns),
|
||||
tunName = TUNTAP.GetName(_tap.ComponentID),
|
||||
fakeDns = Global.Settings.TUNTAP.UseFakeDNS && Flags.SupportFakeDns
|
||||
};
|
||||
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
parameter.proxyServer = $"{server.AutoResolveHostname()}:{server.Port}";
|
||||
else
|
||||
parameter.proxyServer = $"127.0.0.1:{Global.Settings.Socks5LocalPort}";
|
||||
|
||||
StartInstanceAuto(parameter.ToString(), ProcessPriorityClass.RealTime);
|
||||
|
||||
SetupRouteTable(mode);
|
||||
}
|
||||
|
||||
[Verb]
|
||||
public class Tun2SocksParameter : ParameterBase
|
||||
{
|
||||
public string proxyServer { get; set; }
|
||||
|
||||
public string tunAddr { get; set; }
|
||||
|
||||
public string tunMask { get; set; }
|
||||
|
||||
public string tunGw { get; set; }
|
||||
|
||||
public string tunDns { get; set; }
|
||||
|
||||
public string tunName { get; set; }
|
||||
|
||||
public bool fakeDns { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP停止
|
||||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(StopInstance),
|
||||
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"));
|
||||
Logging.Info("设置路由规则");
|
||||
|
||||
#region Rule IPs
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 1:
|
||||
// 代理规则 IP
|
||||
Logging.Info("代理 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
Logging.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
|
||||
else
|
||||
RouteAction(Action.Create, $"{Global.Settings.AioDNS.OtherDNS}/32", RouteType.TUNTAP);
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
// 绕过规则 IP
|
||||
|
||||
// 将 TUN/TAP 网卡权重放到最高
|
||||
SetInterface(RouteType.TUNTAP, 0);
|
||||
|
||||
Logging.Info("绕行 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
|
||||
break;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Logging.Info("绕行 → 服务器 IP");
|
||||
if (!IPAddress.IsLoopback(_serverAddresses))
|
||||
RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound);
|
||||
|
||||
Logging.Info("绕行 → 全局绕过 IP");
|
||||
RouteAction(Action.Create, Global.Settings.BypassIPs, RouteType.Outbound);
|
||||
|
||||
if (mode.Type == 2)
|
||||
{
|
||||
Logging.Info("代理 → 全局");
|
||||
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetInterface(RouteType routeType, int? metric = null)
|
||||
{
|
||||
IAdapter adapter = routeType switch
|
||||
{
|
||||
RouteType.Outbound => _outbound,
|
||||
RouteType.TUNTAP => _tap,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
|
||||
};
|
||||
|
||||
var arguments = $"interface ip set interface {adapter.Index} ";
|
||||
if (metric != null)
|
||||
arguments += $"metric={metric} ";
|
||||
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "netsh",
|
||||
Arguments = arguments,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除绕行规则
|
||||
/// </summary>
|
||||
private bool ClearRouteTable()
|
||||
{
|
||||
RouteAction(Action.Delete, _directIPs, RouteType.Outbound);
|
||||
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
|
||||
_directIPs.Clear();
|
||||
_proxyIPs.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TestFakeDNS()
|
||||
{
|
||||
try
|
||||
{
|
||||
InitInstance("-h");
|
||||
Instance!.Start();
|
||||
return Instance.StandardError.ReadToEnd().Contains("-fakeDns");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0)
|
||||
{
|
||||
foreach (var address in ipNetworks)
|
||||
RouteAction(action, address, routeType, metric);
|
||||
}
|
||||
|
||||
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0)
|
||||
{
|
||||
var s = ipNetwork.Split('/');
|
||||
if (s.Length != 2)
|
||||
{
|
||||
Logging.Warning($"Failed to parse rule {ipNetwork}");
|
||||
return false;
|
||||
}
|
||||
|
||||
IAdapter adapter;
|
||||
List<string> ipList;
|
||||
|
||||
switch (routeType)
|
||||
{
|
||||
case RouteType.TUNTAP:
|
||||
adapter = _tap;
|
||||
ipList = _proxyIPs;
|
||||
break;
|
||||
case RouteType.Outbound:
|
||||
adapter = _outbound;
|
||||
ipList = _directIPs;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null);
|
||||
}
|
||||
|
||||
string network = s[0];
|
||||
var cidr = ushort.Parse(s[1]);
|
||||
string gateway = adapter.Gateway.ToString();
|
||||
var index = adapter.Index;
|
||||
|
||||
bool result;
|
||||
switch (action)
|
||||
{
|
||||
case Action.Create:
|
||||
result = NativeMethods.CreateRoute(network, cidr, gateway, index, metric);
|
||||
ipList.Add(ipNetwork);
|
||||
break;
|
||||
case Action.Delete:
|
||||
result = NativeMethods.DeleteRoute(network, cidr, gateway, index, metric);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(action), action, null);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
Logging.Warning($"Failed to {action} Route on {routeType} Adapter: {ipNetwork} metric {metric}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private enum RouteType
|
||||
{
|
||||
Outbound,
|
||||
TUNTAP
|
||||
}
|
||||
|
||||
private enum Action
|
||||
{
|
||||
Create,
|
||||
Delete
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = @"Beta4";
|
||||
public const string AssemblyVersion = @"1.8.5";
|
||||
private const string Suffix = @"";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
@@ -46,25 +46,25 @@ namespace Netch.Controllers
|
||||
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
|
||||
|
||||
var releases = JsonSerializer.Deserialize<List<Release>>(json)!;
|
||||
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
|
||||
Logging.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
|
||||
LatestRelease = GetLatestRelease(releases, isPreRelease);
|
||||
Global.Logger.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
|
||||
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
|
||||
{
|
||||
Logging.Info("发现新版本");
|
||||
Global.Logger.Info("发现新版本");
|
||||
NewVersionFound?.Invoke(null, new EventArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Info("目前是最新版本");
|
||||
Global.Logger.Info("目前是最新版本");
|
||||
NewVersionNotFound?.Invoke(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is WebException)
|
||||
Logging.Warning($"获取新版本失败: {e.Message}");
|
||||
Global.Logger.Warning($"获取新版本失败: {e.Message}");
|
||||
else
|
||||
Logging.Warning(e.ToString());
|
||||
Global.Logger.Warning(e.ToString());
|
||||
|
||||
NewVersionFoundFailed?.Invoke(null, new EventArgs());
|
||||
}
|
||||
@@ -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,5 +1,4 @@
|
||||
using System;
|
||||
using Netch.Controllers;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -7,10 +6,6 @@ namespace Netch
|
||||
{
|
||||
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
private static readonly Lazy<bool> LazySupportFakeDns = new(() => new TUNTAPController().TestFakeDNS());
|
||||
|
||||
public static bool SupportFakeDns => LazySupportFakeDns.Value;
|
||||
|
||||
public static bool AlwaysShowNewVersionFound { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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,8 +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
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace Netch.Forms
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
IPListBox.Items.AddRange(Global.Settings.BypassIPs.ToArray());
|
||||
IPListBox.Items.AddRange(Global.Settings.TUNTAP.BypassIPs.Cast<object>().ToArray());
|
||||
|
||||
for (var i = 32; i >= 1; i--)
|
||||
PrefixComboBox.Items.Add(i);
|
||||
@@ -31,7 +32,7 @@ namespace Netch.Forms
|
||||
if (!string.IsNullOrEmpty(IPTextBox.Text))
|
||||
{
|
||||
if (IPAddress.TryParse(IPTextBox.Text, out var address))
|
||||
IPListBox.Items.Add(string.Format("{0}/{1}", address, PrefixComboBox.SelectedItem));
|
||||
IPListBox.Items.Add($"{address}/{PrefixComboBox.SelectedItem}");
|
||||
else
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a correct IP address"));
|
||||
}
|
||||
@@ -51,9 +52,9 @@ namespace Netch.Forms
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Settings.BypassIPs.Clear();
|
||||
Global.Settings.TUNTAP.BypassIPs.Clear();
|
||||
foreach (var ip in IPListBox.Items)
|
||||
Global.Settings.BypassIPs.Add((string) ip);
|
||||
Global.Settings.TUNTAP.BypassIPs.Add((string)ip);
|
||||
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
|
||||
6
Netch/Forms/LogForm.Designer.cs
generated
6
Netch/Forms/LogForm.Designer.cs
generated
@@ -40,7 +40,7 @@ namespace Netch.Forms
|
||||
this.richTextBox1.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.richTextBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.richTextBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.richTextBox1.Name = "richTextBox1";
|
||||
this.richTextBox1.ReadOnly = true;
|
||||
@@ -54,14 +54,14 @@ namespace Netch.Forms
|
||||
this.checkBox1.AutoSize = true;
|
||||
this.checkBox1.Location = new System.Drawing.Point(12, 297);
|
||||
this.checkBox1.Name = "checkBox1";
|
||||
this.checkBox1.Size = new System.Drawing.Size(102, 16);
|
||||
this.checkBox1.Size = new System.Drawing.Size(101, 21);
|
||||
this.checkBox1.TabIndex = 1;
|
||||
this.checkBox1.Text = "Scroll to End";
|
||||
this.checkBox1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// LogForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(454, 318);
|
||||
this.ControlBox = false;
|
||||
|
||||
@@ -16,13 +16,13 @@ namespace Netch.Forms
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
protected override void OnLoad(EventArgs? e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
Parent_Move(null!, null!);
|
||||
}
|
||||
|
||||
private void Parent_Move(object sender, EventArgs e)
|
||||
private void Parent_Move(object? sender, EventArgs? e)
|
||||
{
|
||||
var cl = Location;
|
||||
var fl = _parent.Location;
|
||||
@@ -32,7 +32,7 @@ namespace Netch.Forms
|
||||
Location = cl;
|
||||
}
|
||||
|
||||
private void Parent_Activated(object sender, EventArgs e)
|
||||
private void Parent_Activated(object? sender, EventArgs? e)
|
||||
{
|
||||
SetWindowPos(Handle,
|
||||
HWND.HWND_TOPMOST,
|
||||
@@ -51,7 +51,7 @@ namespace Netch.Forms
|
||||
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
private void richTextBox1_TextChanged(object sender, System.EventArgs e)
|
||||
private void richTextBox1_TextChanged(object? sender, EventArgs? e)
|
||||
{
|
||||
if (!checkBox1.Checked)
|
||||
return;
|
||||
@@ -60,19 +60,19 @@ namespace Netch.Forms
|
||||
richTextBox1.ScrollToCaret();
|
||||
}
|
||||
|
||||
private void Notifycation_Load(object sender, EventArgs e)
|
||||
private void Notifycation_Load(object? sender, EventArgs? e)
|
||||
{
|
||||
_parent.LocationChanged += Parent_Move;
|
||||
_parent.SizeChanged += Parent_Move;
|
||||
_parent.Activated += Parent_Activated;
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
protected override void OnClosing(CancelEventArgs? e)
|
||||
{
|
||||
_parent.Activated -= Parent_Activated;
|
||||
_parent.LocationChanged -= Parent_Move;
|
||||
_parent.SizeChanged -= Parent_Move;
|
||||
base.OnClosing(e);
|
||||
base.OnClosing(e!);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Netch/Forms/LogForm.resx
Normal file
60
Netch/Forms/LogForm.resx
Normal file
@@ -0,0 +1,60 @@
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
74
Netch/Forms/MainForm.Designer.cs
generated
74
Netch/Forms/MainForm.Designer.cs
generated
@@ -38,16 +38,12 @@
|
||||
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ManageSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OpenDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CleanDNSCacheToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateACLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.updateACLWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallTapDriverToolStripMenuItem = 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();
|
||||
@@ -61,7 +57,7 @@
|
||||
this.ModeLabel = new System.Windows.Forms.Label();
|
||||
this.ServerLabel = new System.Windows.Forms.Label();
|
||||
this.ProfileNameText = new System.Windows.Forms.TextBox();
|
||||
this.ModeComboBox = new System.Windows.Forms.SearchComboBox();
|
||||
this.ModeComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.ServerComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.EditServerPictureBox = new System.Windows.Forms.PictureBox();
|
||||
@@ -171,8 +167,7 @@
|
||||
//
|
||||
this.SubscribeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ManageSubscribeLinksToolStripMenuItem,
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem,
|
||||
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem});
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem});
|
||||
this.SubscribeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.SubscribeToolStripMenuItem.Name = "SubscribeToolStripMenuItem";
|
||||
this.SubscribeToolStripMenuItem.Size = new System.Drawing.Size(77, 21);
|
||||
@@ -181,34 +176,24 @@
|
||||
// ManageSubscribeLinksToolStripMenuItem
|
||||
//
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Name = "ManageSubscribeLinksToolStripMenuItem";
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Text = "Manage Subscribe Links";
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.ManageSubscribeLinksToolStripMenuItem_Click);
|
||||
//
|
||||
// UpdateServersFromSubscribeLinksToolStripMenuItem
|
||||
//
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksToolStripMenuItem";
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Text = "Update Servers From Subscribe Links";
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscribeLinksToolStripMenuItem_Click);
|
||||
//
|
||||
// UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem
|
||||
//
|
||||
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem";
|
||||
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
|
||||
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Text = "Update Servers From Subscribe Links With Proxy";
|
||||
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem_Click);
|
||||
//
|
||||
// OptionsToolStripMenuItem
|
||||
//
|
||||
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.OpenDirectoryToolStripMenuItem,
|
||||
this.ShowHideConsoleToolStripMenuItem,
|
||||
this.CleanDNSCacheToolStripMenuItem,
|
||||
this.UpdateACLToolStripMenuItem,
|
||||
this.updateACLWithProxyToolStripMenuItem,
|
||||
this.updatePACToolStripMenuItem,
|
||||
this.UninstallServiceToolStripMenuItem,
|
||||
this.UninstallTapDriverToolStripMenuItem,
|
||||
this.removeNetchFirewallRulesToolStripMenuItem});
|
||||
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.OptionsToolStripMenuItem.Name = "OptionsToolStripMenuItem";
|
||||
@@ -229,27 +214,6 @@
|
||||
this.CleanDNSCacheToolStripMenuItem.Text = "Clean DNS Cache";
|
||||
this.CleanDNSCacheToolStripMenuItem.Click += new System.EventHandler(this.CleanDNSCacheToolStripMenuItem_Click);
|
||||
//
|
||||
// UpdateACLToolStripMenuItem
|
||||
//
|
||||
this.UpdateACLToolStripMenuItem.Name = "UpdateACLToolStripMenuItem";
|
||||
this.UpdateACLToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.UpdateACLToolStripMenuItem.Text = "Update ACL";
|
||||
this.UpdateACLToolStripMenuItem.Click += new System.EventHandler(this.updateACLToolStripMenuItem_Click);
|
||||
//
|
||||
// updateACLWithProxyToolStripMenuItem
|
||||
//
|
||||
this.updateACLWithProxyToolStripMenuItem.Name = "updateACLWithProxyToolStripMenuItem";
|
||||
this.updateACLWithProxyToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.updateACLWithProxyToolStripMenuItem.Text = "Update ACL with proxy";
|
||||
this.updateACLWithProxyToolStripMenuItem.Click += new System.EventHandler(this.updateACLWithProxyToolStripMenuItem_Click);
|
||||
//
|
||||
// updatePACToolStripMenuItem
|
||||
//
|
||||
this.updatePACToolStripMenuItem.Name = "updatePACToolStripMenuItem";
|
||||
this.updatePACToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.updatePACToolStripMenuItem.Text = "Update PAC";
|
||||
this.updatePACToolStripMenuItem.Click += new System.EventHandler(this.updatePACToolStripMenuItem_Click);
|
||||
//
|
||||
// UninstallServiceToolStripMenuItem
|
||||
//
|
||||
this.UninstallServiceToolStripMenuItem.Name = "UninstallServiceToolStripMenuItem";
|
||||
@@ -257,13 +221,6 @@
|
||||
this.UninstallServiceToolStripMenuItem.Text = "Uninstall NF Service";
|
||||
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
|
||||
//
|
||||
// UninstallTapDriverToolStripMenuItem
|
||||
//
|
||||
this.UninstallTapDriverToolStripMenuItem.Name = "UninstallTapDriverToolStripMenuItem";
|
||||
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.UninstallTapDriverToolStripMenuItem.Text = "Uninstall TUN/TAP driver";
|
||||
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.UninstallTapDriverToolStripMenuItem_Click);
|
||||
//
|
||||
// removeNetchFirewallRulesToolStripMenuItem
|
||||
//
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Name = "removeNetchFirewallRulesToolStripMenuItem";
|
||||
@@ -271,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[] {
|
||||
@@ -414,9 +378,9 @@
|
||||
//
|
||||
// ModeComboBox
|
||||
//
|
||||
this.ModeComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
|
||||
this.ModeComboBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ModeComboBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
|
||||
this.ModeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ModeComboBox.FormattingEnabled = true;
|
||||
this.ModeComboBox.IntegralHeight = false;
|
||||
this.ModeComboBox.Location = new System.Drawing.Point(54, 33);
|
||||
@@ -732,7 +696,7 @@
|
||||
this.Controls.Add(this.MenuStrip);
|
||||
this.Controls.Add(this.StatusStrip);
|
||||
this.Controls.Add(this.flowLayoutPanel1);
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
|
||||
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
@@ -788,7 +752,7 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem ImportServersFromClipboardToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ManageSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.MenuStrip MenuStrip;
|
||||
private System.Windows.Forms.SearchComboBox ModeComboBox;
|
||||
private System.Windows.Forms.ComboBox ModeComboBox;
|
||||
private System.Windows.Forms.Label ModeLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem ModeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem HelpToolStripMenuItem;
|
||||
@@ -801,7 +765,6 @@
|
||||
private System.Windows.Forms.Label ProfileLabel;
|
||||
private System.Windows.Forms.TextBox ProfileNameText;
|
||||
private System.Windows.Forms.TableLayoutPanel ProfileTable;
|
||||
private System.Windows.Forms.ToolStripMenuItem UninstallTapDriverToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem CheckForUpdatesToolStripMenuItem;
|
||||
private System.Windows.Forms.ComboBox ServerComboBox;
|
||||
private System.Windows.Forms.Label ServerLabel;
|
||||
@@ -815,10 +778,7 @@
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.ToolStripMenuItem UninstallServiceToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateACLToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem updateACLWithProxyToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UploadSpeedLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UsedBandwidthLabel;
|
||||
private System.Windows.Forms.ToolStripLabel NewVersionLabel;
|
||||
@@ -831,6 +791,6 @@
|
||||
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
|
||||
private System.Windows.Forms.ToolStripMenuItem updatePACToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Services;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Hide();
|
||||
new Route().ShowDialog();
|
||||
Show();
|
||||
}
|
||||
|
||||
#region Start
|
||||
|
||||
private readonly Dictionary<string, object> _mainFormText = new();
|
||||
@@ -41,27 +38,12 @@ namespace Netch.Forms
|
||||
|
||||
#region i18N Translations
|
||||
|
||||
_mainFormText.Add(UninstallServiceToolStripMenuItem.Name, new[] {"Uninstall {0}", "NF Service"});
|
||||
_mainFormText.Add(UninstallTapDriverToolStripMenuItem.Name, new[] {"Uninstall {0}", "TUN/TAP driver"});
|
||||
_mainFormText.Add(UninstallServiceToolStripMenuItem.Name, new[] { "Uninstall {0}", "NF Service" });
|
||||
|
||||
#endregion
|
||||
|
||||
// 监听电源事件
|
||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
||||
|
||||
ModeComboBox.KeyUp += (_, args) =>
|
||||
{
|
||||
switch (args.KeyData)
|
||||
{
|
||||
case Keys.Escape:
|
||||
{
|
||||
SelectLastMode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
}
|
||||
|
||||
private void AddAddServerToolStripMenuItems()
|
||||
@@ -73,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);
|
||||
}
|
||||
@@ -102,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(Global.Settings.UseProxyToUpdateSubscription).Wait();
|
||||
await UpdateServersFromSubscribe();
|
||||
|
||||
// 打开软件时启动加速,产生开始按钮点击事件
|
||||
if (Global.Settings.StartWhenOpened)
|
||||
ControlButton_Click(null, null);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
private void RecordSize()
|
||||
@@ -197,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);
|
||||
}
|
||||
@@ -235,16 +218,15 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private void AddServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private void AddServerToolStripMenuItem_Click([NotNull] object? sender, EventArgs? e)
|
||||
{
|
||||
var s = ((ToolStripMenuItem) sender).Text;
|
||||
if (sender == null)
|
||||
throw new ArgumentNullException(nameof(sender));
|
||||
|
||||
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();
|
||||
@@ -262,6 +244,13 @@ namespace Netch.Forms
|
||||
Show();
|
||||
}
|
||||
|
||||
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Hide();
|
||||
new Route().ShowDialog();
|
||||
Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Subscription
|
||||
@@ -276,33 +265,16 @@ namespace Netch.Forms
|
||||
|
||||
private async void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Settings.UseProxyToUpdateSubscription = false;
|
||||
await UpdateServersFromSubscribe();
|
||||
}
|
||||
|
||||
private async void UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Settings.UseProxyToUpdateSubscription = true;
|
||||
await UpdateServersFromSubscribe(true);
|
||||
}
|
||||
|
||||
private async Task UpdateServersFromSubscribe(bool useProxy = false)
|
||||
private async Task UpdateServersFromSubscribe()
|
||||
{
|
||||
void DisableItems(bool v)
|
||||
{
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ProfileGroupBox.Enabled = ControlButton.Enabled = v;
|
||||
}
|
||||
|
||||
var server = ServerComboBox.SelectedItem as Server;
|
||||
if (useProxy)
|
||||
{
|
||||
if (server == null)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.SubscribeLink.Count <= 0)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("No subscription link"));
|
||||
@@ -311,22 +283,10 @@ namespace Netch.Forms
|
||||
|
||||
StatusText(i18N.Translate("Starting update subscription"));
|
||||
DisableItems(false);
|
||||
|
||||
try
|
||||
{
|
||||
string? proxyServer = null;
|
||||
if (useProxy)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.StartAsync(server!, mode);
|
||||
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
}
|
||||
|
||||
await Subscription.UpdateServersAsync(proxyServer);
|
||||
await Subscription.UpdateServersAsync();
|
||||
|
||||
LoadServers();
|
||||
Configuration.Save();
|
||||
@@ -335,13 +295,10 @@ namespace Netch.Forms
|
||||
catch (Exception e)
|
||||
{
|
||||
NotifyTip(i18N.Translate("update servers failed") + "\n" + e.Message, info: false);
|
||||
Logging.Error("更新服务器 失败!" + e);
|
||||
Global.Logger.Error("更新服务器 失败!" + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (useProxy)
|
||||
await MainController.StopAsync();
|
||||
|
||||
DisableItems(true);
|
||||
}
|
||||
}
|
||||
@@ -350,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)
|
||||
@@ -389,7 +343,7 @@ namespace Netch.Forms
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
NativeMethods.RefreshDNSCache();
|
||||
DnsUtils.ClearCache();
|
||||
});
|
||||
|
||||
@@ -405,121 +359,16 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private void updateACLWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
UpdateACL(true);
|
||||
}
|
||||
|
||||
private void updateACLToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
UpdateACL(false);
|
||||
}
|
||||
|
||||
private async void UpdateACL(bool useProxy)
|
||||
{
|
||||
Enabled = false;
|
||||
StatusText(i18N.TranslateFormat("Updating {0}", "ACL"));
|
||||
try
|
||||
{
|
||||
if (useProxy)
|
||||
{
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.StartAsync(server, mode);
|
||||
}
|
||||
}
|
||||
|
||||
var req = WebUtil.CreateRequest(Global.Settings.ACL);
|
||||
if (useProxy)
|
||||
req.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
|
||||
|
||||
await WebUtil.DownloadFileAsync(req, Path.Combine(Global.NetchDir, Constants.UserACL));
|
||||
NotifyTip(i18N.Translate("ACL updated successfully"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NotifyTip(i18N.Translate("ACL update failed") + "\n" + e.Message, info: false);
|
||||
Logging.Error("更新 ACL 失败!" + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (useProxy)
|
||||
await MainController.StopAsync();
|
||||
|
||||
StatusText();
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void updatePACToolStripMenuItem_Click(object sender, EventArgs eventArgs)
|
||||
{
|
||||
Enabled = false;
|
||||
|
||||
StatusText(i18N.TranslateFormat("Updating {0}", "PAC"));
|
||||
try
|
||||
{
|
||||
var req = WebUtil.CreateRequest(Global.Settings.PAC);
|
||||
|
||||
var pac = Path.Combine(Global.NetchDir, "bin\\pac.txt");
|
||||
|
||||
await WebUtil.DownloadFileAsync(req, pac);
|
||||
|
||||
NotifyTip(i18N.Translate("PAC updated successfully"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NotifyTip(i18N.Translate("PAC update failed") + "\n" + e.Message, info: false);
|
||||
Logging.Error("更新 PAC 失败!" + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
StatusText();
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Enabled = false;
|
||||
StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (NFController.UninstallDriver())
|
||||
NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
StatusText();
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
var task = Task.Run(NFController.UninstallDriver);
|
||||
|
||||
private async void UninstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Enabled = false;
|
||||
StatusText(i18N.TranslateFormat("Uninstalling {0}", "TUN/TAP driver"));
|
||||
try
|
||||
{
|
||||
await Task.Run(TUNTAP.deltapall);
|
||||
NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logging.Error($"卸载 TUN/TAP 适配器失败: {exception}");
|
||||
if (await task)
|
||||
NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -533,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>
|
||||
@@ -566,19 +422,16 @@ 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)
|
||||
{
|
||||
if (exception is not MessageException)
|
||||
{
|
||||
Logging.Error($"更新失败: {exception}");
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
Global.Logger.Error($"更新失败: {exception}");
|
||||
Global.Logger.ShowLog();
|
||||
}
|
||||
|
||||
NotifyTip(exception.Message, info: false);
|
||||
@@ -610,29 +463,25 @@ 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;
|
||||
}
|
||||
|
||||
// 清除模式搜索框文本选择
|
||||
ModeComboBox.Select(0, 0);
|
||||
|
||||
State = State.Starting;
|
||||
|
||||
try
|
||||
@@ -660,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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -714,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)
|
||||
@@ -756,28 +601,30 @@ 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
|
||||
{
|
||||
ServerHelper.DelayTestHelper.TestDelayFinished += OnTestDelayFinished;
|
||||
_ = Task.Run(ServerHelper.DelayTestHelper.TestAllDelay);
|
||||
|
||||
void OnTestDelayFinished(object o1, EventArgs e1)
|
||||
void OnTestDelayFinished(object? o1, EventArgs? e1)
|
||||
{
|
||||
Refresh();
|
||||
|
||||
ServerHelper.DelayTestHelper.TestDelayFinished -= OnTestDelayFinished;
|
||||
Enabled = true;
|
||||
StatusText();
|
||||
Enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -836,7 +683,7 @@ namespace Netch.Forms
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
public void SelectLastMode()
|
||||
private void SelectLastMode()
|
||||
{
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ModeComboBoxSelectedIndex > 0 && Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
|
||||
@@ -852,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
|
||||
{
|
||||
@@ -869,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!));
|
||||
@@ -878,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();
|
||||
@@ -904,7 +751,7 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
ModeHelper.Delete((Models.Mode) ModeComboBox.SelectedItem);
|
||||
ModeHelper.Delete((Models.Mode)ModeComboBox.SelectedItem);
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
@@ -921,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();
|
||||
@@ -947,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)
|
||||
{
|
||||
@@ -980,7 +827,6 @@ namespace Netch.Forms
|
||||
private void ActiveProfile(Profile profile)
|
||||
{
|
||||
ProfileNameText.Text = profile.ProfileName;
|
||||
ModeComboBox.ResetCompletionList();
|
||||
|
||||
var server = ServerComboBox.Items.Cast<Server>().FirstOrDefault(s => s.Remark.Equals(profile.ServerRemark));
|
||||
var mode = ModeComboBox.Items.Cast<Models.Mode>().FirstOrDefault(m => m.Remark.Equals(profile.ModeRemark));
|
||||
@@ -997,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;
|
||||
@@ -1010,10 +856,13 @@ namespace Netch.Forms
|
||||
return profile;
|
||||
}
|
||||
|
||||
private async void ProfileButton_Click(object sender, EventArgs e)
|
||||
private async void ProfileButton_Click([NotNull] object? sender, EventArgs? e)
|
||||
{
|
||||
var profileButton = (Button) sender;
|
||||
var profile = (Profile?) profileButton.Tag;
|
||||
if (sender == null)
|
||||
throw new ArgumentNullException(nameof(sender));
|
||||
|
||||
var profileButton = (Button)sender;
|
||||
var profile = (Profile?)profileButton.Tag;
|
||||
var index = ProfileTable.Controls.IndexOf(profileButton);
|
||||
|
||||
switch (ModifierKeys)
|
||||
@@ -1099,9 +948,7 @@ namespace Netch.Forms
|
||||
EditServerPictureBox.Enabled = DeleteModePictureBox.Enabled = DeleteServerPictureBox.Enabled = enabled;
|
||||
|
||||
// 启动需要禁用的控件
|
||||
UninstallServiceToolStripMenuItem.Enabled = UpdateACLToolStripMenuItem.Enabled = updateACLWithProxyToolStripMenuItem.Enabled =
|
||||
updatePACToolStripMenuItem.Enabled = UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
|
||||
UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Enabled = UninstallTapDriverToolStripMenuItem.Enabled = enabled;
|
||||
UninstallServiceToolStripMenuItem.Enabled = UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = enabled;
|
||||
}
|
||||
|
||||
_state = value;
|
||||
@@ -1153,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()
|
||||
@@ -1255,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;
|
||||
}
|
||||
@@ -1271,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))
|
||||
{
|
||||
@@ -1303,9 +1149,11 @@ namespace Netch.Forms
|
||||
{
|
||||
NatTypeStatusText(result ?? "Error");
|
||||
}
|
||||
|
||||
NttTested = true;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
_natTestLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1326,7 +1174,7 @@ namespace Netch.Forms
|
||||
if (!IsWaiting())
|
||||
{
|
||||
_resumeFlag = true;
|
||||
Logging.Info("操作系统即将挂起,自动停止");
|
||||
Global.Logger.Info("操作系统即将挂起,自动停止");
|
||||
ControlButton_Click(null, null);
|
||||
}
|
||||
|
||||
@@ -1335,7 +1183,7 @@ namespace Netch.Forms
|
||||
if (_resumeFlag)
|
||||
{
|
||||
_resumeFlag = false;
|
||||
Logging.Info("操作系统即将从挂起状态继续,自动重启");
|
||||
Global.Logger.Info("操作系统即将从挂起状态继续,自动重启");
|
||||
ControlButton_Click(null, null);
|
||||
}
|
||||
|
||||
@@ -1379,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);
|
||||
@@ -1414,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!);
|
||||
}
|
||||
@@ -1428,7 +1275,7 @@ namespace Netch.Forms
|
||||
UpdateChecker.NewVersionFound -= OnUpdateCheckerOnNewVersionFound;
|
||||
}
|
||||
|
||||
void OnUpdateCheckerOnNewVersionFound(object o, EventArgs eventArgs)
|
||||
void OnUpdateCheckerOnNewVersionFound(object? o, EventArgs? eventArgs)
|
||||
{
|
||||
NotifyTip($"{i18N.Translate(@"New version available", ": ")}{UpdateChecker.LatestVersionNumber}");
|
||||
NewVersionLabel.Text = i18N.Translate("New version available");
|
||||
@@ -1534,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;
|
||||
|
||||
// 绘制背景颜色
|
||||
@@ -1551,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);
|
||||
@@ -1573,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,64 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
@@ -117,16 +57,4 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="MenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="StatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>130, 17</value>
|
||||
</metadata>
|
||||
<metadata name="NotifyIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>246, 17</value>
|
||||
</metadata>
|
||||
<metadata name="NotifyMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>359, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -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,14 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using 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
|
||||
{
|
||||
@@ -25,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();
|
||||
@@ -63,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);
|
||||
@@ -117,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"));
|
||||
@@ -135,12 +135,11 @@ namespace Netch.Forms.Mode
|
||||
|
||||
var mode = new Models.Mode(fullName)
|
||||
{
|
||||
BypassChina = false,
|
||||
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"));
|
||||
@@ -149,7 +148,7 @@ namespace Netch.Forms.Mode
|
||||
Close();
|
||||
}
|
||||
|
||||
private void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
private void RemarkTextBox_TextChanged(object? sender, EventArgs? e)
|
||||
{
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
@@ -195,7 +194,8 @@ namespace Netch.Forms.Mode
|
||||
foreach (string dir in Directory.GetDirectories(directory))
|
||||
ScanDirectory(dir, list, maxCount);
|
||||
|
||||
list.AddRange(Directory.GetFiles(directory).Select(Path.GetFileName).Where(s => s.EndsWith(".exe")).Select(s => s.ToRegexString()));
|
||||
list.AddRange(
|
||||
Directory.GetFiles(directory).Select(s => Path.GetFileName(s)).Where(s => s.EndsWith(".exe")).Select(s => s.ToRegexString()));
|
||||
|
||||
if (maxCount != 0 && list.Count > maxCount)
|
||||
throw new Exception("The number of results is greater than maxCount");
|
||||
@@ -203,7 +203,7 @@ namespace Netch.Forms.Mode
|
||||
|
||||
private void ValidationButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (NFController.CheckRules(Rules, out var results))
|
||||
if (!NFController.CheckRules(Rules, out var results))
|
||||
MessageBoxX.Show(NFController.GenerateInvalidRulesMessage(results), LogLevel.WARNING);
|
||||
else
|
||||
MessageBoxX.Show("Fine");
|
||||
|
||||
120
Netch/Forms/Mode/Process.resx
Normal file
120
Netch/Forms/Mode/Process.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
14
Netch/Forms/Mode/Route.Designer.cs
generated
14
Netch/Forms/Mode/Route.Designer.cs
generated
@@ -72,7 +72,7 @@ namespace Netch.Forms.Mode
|
||||
this.comboBox1.FormattingEnabled = true;
|
||||
this.comboBox1.Location = new System.Drawing.Point(84, 49);
|
||||
this.comboBox1.Name = "comboBox1";
|
||||
this.comboBox1.Size = new System.Drawing.Size(138, 20);
|
||||
this.comboBox1.Size = new System.Drawing.Size(138, 25);
|
||||
this.comboBox1.TabIndex = 11;
|
||||
//
|
||||
// FilenameLabel
|
||||
@@ -80,7 +80,7 @@ namespace Netch.Forms.Mode
|
||||
this.FilenameLabel.AutoSize = true;
|
||||
this.FilenameLabel.Location = new System.Drawing.Point(12, 79);
|
||||
this.FilenameLabel.Name = "FilenameLabel";
|
||||
this.FilenameLabel.Size = new System.Drawing.Size(53, 12);
|
||||
this.FilenameLabel.Size = new System.Drawing.Size(59, 17);
|
||||
this.FilenameLabel.TabIndex = 6;
|
||||
this.FilenameLabel.Text = "Filename";
|
||||
//
|
||||
@@ -89,7 +89,7 @@ namespace Netch.Forms.Mode
|
||||
this.FilenameTextBox.Location = new System.Drawing.Point(84, 76);
|
||||
this.FilenameTextBox.Name = "FilenameTextBox";
|
||||
this.FilenameTextBox.ReadOnly = true;
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(250, 21);
|
||||
this.FilenameTextBox.Size = new System.Drawing.Size(250, 23);
|
||||
this.FilenameTextBox.TabIndex = 5;
|
||||
//
|
||||
// ActionLabel
|
||||
@@ -97,7 +97,7 @@ namespace Netch.Forms.Mode
|
||||
this.ActionLabel.AutoSize = true;
|
||||
this.ActionLabel.Location = new System.Drawing.Point(12, 52);
|
||||
this.ActionLabel.Name = "ActionLabel";
|
||||
this.ActionLabel.Size = new System.Drawing.Size(41, 12);
|
||||
this.ActionLabel.Size = new System.Drawing.Size(44, 17);
|
||||
this.ActionLabel.TabIndex = 0;
|
||||
this.ActionLabel.Text = "Action";
|
||||
//
|
||||
@@ -105,7 +105,7 @@ namespace Netch.Forms.Mode
|
||||
//
|
||||
this.RemarkTextBox.Location = new System.Drawing.Point(84, 22);
|
||||
this.RemarkTextBox.Name = "RemarkTextBox";
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(250, 21);
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(250, 23);
|
||||
this.RemarkTextBox.TabIndex = 1;
|
||||
this.RemarkTextBox.TextChanged += new System.EventHandler(this.RemarkTextBox_TextChanged);
|
||||
//
|
||||
@@ -114,7 +114,7 @@ namespace Netch.Forms.Mode
|
||||
this.RemarkLabel.AutoSize = true;
|
||||
this.RemarkLabel.Location = new System.Drawing.Point(12, 25);
|
||||
this.RemarkLabel.Name = "RemarkLabel";
|
||||
this.RemarkLabel.Size = new System.Drawing.Size(41, 12);
|
||||
this.RemarkLabel.Size = new System.Drawing.Size(53, 17);
|
||||
this.RemarkLabel.TabIndex = 0;
|
||||
this.RemarkLabel.Text = "Remark";
|
||||
//
|
||||
@@ -161,7 +161,7 @@ namespace Netch.Forms.Mode
|
||||
//
|
||||
// Route
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(356, 419);
|
||||
this.Controls.Add(this.ConfigurationGroupBox);
|
||||
|
||||
@@ -1,39 +1,23 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
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
|
||||
{
|
||||
class Item
|
||||
{
|
||||
private string _text;
|
||||
|
||||
public Item(int value, string text)
|
||||
{
|
||||
_text = text;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => i18N.Translate(_text);
|
||||
set => _text = value;
|
||||
}
|
||||
|
||||
public int Value { get; set; }
|
||||
}
|
||||
|
||||
private readonly Item[] _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;
|
||||
@@ -41,8 +25,8 @@ namespace Netch.Forms.Mode
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
comboBox1.DataSource = _items;
|
||||
comboBox1.ValueMember = "Value";
|
||||
comboBox1.DisplayMember = "Text";
|
||||
comboBox1.ValueMember = nameof(TagItem<int>.Value);
|
||||
comboBox1.DisplayMember = nameof(TagItem<int>.Text);
|
||||
}
|
||||
|
||||
private void Route_Load(object sender, EventArgs e)
|
||||
@@ -55,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);
|
||||
@@ -78,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"));
|
||||
@@ -97,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"));
|
||||
@@ -110,12 +94,9 @@ namespace Netch.Forms.Mode
|
||||
Close();
|
||||
}
|
||||
|
||||
private void RemarkTextBox_TextChanged(object sender, EventArgs e)
|
||||
private void RemarkTextBox_TextChanged(object? sender, EventArgs? e)
|
||||
{
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text);
|
||||
}));
|
||||
BeginInvoke(new Action(() => { FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Netch/Forms/Mode/Route.resx
Normal file
60
Netch/Forms/Mode/Route.resx
Normal file
@@ -0,0 +1,60 @@
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -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
|
||||
|
||||
472
Netch/Forms/SettingForm.Designer.cs
generated
472
Netch/Forms/SettingForm.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -26,23 +26,18 @@ namespace Netch.Forms
|
||||
#region General
|
||||
|
||||
BindTextBox<ushort>(Socks5PortTextBox,
|
||||
p => p.ToString() != HTTPPortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
|
||||
p => p.ToString() != HTTPPortTextBox.Text,
|
||||
p => Global.Settings.Socks5LocalPort = p,
|
||||
Global.Settings.Socks5LocalPort);
|
||||
|
||||
BindTextBox<ushort>(HTTPPortTextBox,
|
||||
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
|
||||
p => p.ToString() != Socks5PortTextBox.Text,
|
||||
p => Global.Settings.HTTPLocalPort = p,
|
||||
Global.Settings.HTTPLocalPort);
|
||||
|
||||
BindTextBox<ushort>(RedirectorTextBox,
|
||||
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != HTTPPortTextBox.Text,
|
||||
p => Global.Settings.RedirectorTCPPort = p,
|
||||
Global.Settings.RedirectorTCPPort);
|
||||
|
||||
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);
|
||||
|
||||
@@ -68,7 +63,7 @@ namespace Netch.Forms
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Warning($"Load stun.txt failed: {e.Message}");
|
||||
Global.Logger.Warning($"Load stun.txt failed: {e.Message}");
|
||||
stuns = null;
|
||||
}
|
||||
|
||||
@@ -97,33 +92,33 @@ namespace Netch.Forms
|
||||
Global.Settings.STUN_Server + ":" + Global.Settings.STUN_Server_Port,
|
||||
stuns);
|
||||
|
||||
BindTextBox<string>(AclAddrTextBox, s => true, s => Global.Settings.ACL = s, Global.Settings.ACL);
|
||||
|
||||
BindListComboBox(LanguageComboBox,
|
||||
o => Global.Settings.Language = o.ToString(),
|
||||
i18N.GetTranslateList().Cast<object>().ToArray(),
|
||||
Global.Settings.Language);
|
||||
BindListComboBox(LanguageComboBox, o => Global.Settings.Language = o.ToString(), i18N.GetTranslateList(), Global.Settings.Language);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Process Mode
|
||||
|
||||
BindCheckBox(DNSRedirectorCheckBox, b => Global.Settings.RedirectDNS = b, Global.Settings.RedirectDNS);
|
||||
BindCheckBox(DNSHijackCheckBox, b => Global.Settings.Redirector.DNSHijack = b, Global.Settings.Redirector.DNSHijack);
|
||||
|
||||
BindTextBox(RDRDNSTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.RedirectDNSAddr = s, Global.Settings.RedirectDNSAddr);
|
||||
BindTextBox(DNSHijackHostTextBox, s => true, s => Global.Settings.Redirector.DNSHijackHost = s, Global.Settings.Redirector.DNSHijackHost);
|
||||
|
||||
BindCheckBox(ICMPRedirectorCheckBox, b => Global.Settings.RedirectICMP = b, Global.Settings.RedirectICMP);
|
||||
BindCheckBox(ICMPHijackCheckBox, b => Global.Settings.Redirector.ICMPHijack = b, Global.Settings.Redirector.ICMPHijack);
|
||||
|
||||
BindTextBox(ModifiedICMPTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.RedirectICMPAddr = s, Global.Settings.RedirectICMPAddr);
|
||||
BindTextBox(ICMPHijackHostTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.Redirector.ICMPHost = s,
|
||||
Global.Settings.Redirector.ICMPHost);
|
||||
|
||||
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.RedirectorSS = s, Global.Settings.RedirectorSS);
|
||||
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.Redirector.RedirectorSS = s, Global.Settings.Redirector.RedirectorSS);
|
||||
|
||||
BindCheckBox(ChildProcessHandleCheckBox, s => Global.Settings.ChildProcessHandle = s, Global.Settings.ChildProcessHandle);
|
||||
BindCheckBox(ChildProcessHandleCheckBox,
|
||||
s => Global.Settings.Redirector.ChildProcessHandle = s,
|
||||
Global.Settings.Redirector.ChildProcessHandle);
|
||||
|
||||
BindListComboBox(ProcessProxyProtocolComboBox,
|
||||
s => Global.Settings.ProcessProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)).Cast<object>().ToArray(),
|
||||
Global.Settings.ProcessProxyProtocol.ToString());
|
||||
s => Global.Settings.Redirector.ProxyProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)),
|
||||
Global.Settings.Redirector.ProxyProtocol.ToString());
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -147,16 +142,15 @@ namespace Netch.Forms
|
||||
BindCheckBox(UseCustomDNSCheckBox, b => { Global.Settings.TUNTAP.UseCustomDNS = b; }, Global.Settings.TUNTAP.UseCustomDNS);
|
||||
|
||||
BindTextBox(TUNTAPDNSTextBox,
|
||||
s => !UseCustomDNSCheckBox.Checked || DnsUtils.TrySplit(s, out _, 2),
|
||||
_ => true,
|
||||
s =>
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
Global.Settings.TUNTAP.DNS = DnsUtils.Split(s).ToList();
|
||||
Global.Settings.TUNTAP.HijackDNS = s;
|
||||
},
|
||||
DnsUtils.Join(Global.Settings.TUNTAP.DNS));
|
||||
Global.Settings.TUNTAP.HijackDNS);
|
||||
|
||||
BindCheckBox(ProxyDNSCheckBox, b => Global.Settings.TUNTAP.ProxyDNS = b, Global.Settings.TUNTAP.ProxyDNS);
|
||||
BindCheckBox(UseFakeDNSCheckBox, b => Global.Settings.TUNTAP.UseFakeDNS = b, Global.Settings.TUNTAP.UseFakeDNS);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -217,17 +211,14 @@ namespace Netch.Forms
|
||||
|
||||
#region AioDNS
|
||||
|
||||
BindTextBox(AioDNSRulePathTextBox, s => 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(ChinaDNSTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.AioDNS.ChinaDNS = s,
|
||||
Global.Settings.AioDNS.ChinaDNS);
|
||||
BindTextBox(OtherDNSTextBox, _ => true, s => Global.Settings.AioDNS.OtherDNS = s, Global.Settings.AioDNS.OtherDNS);
|
||||
|
||||
BindTextBox(OtherDNSTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
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
|
||||
}
|
||||
@@ -235,13 +226,12 @@ namespace Netch.Forms
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
|
||||
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Flags.SupportFakeDns)));
|
||||
}
|
||||
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object? sender, EventArgs? e)
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any() ? DnsUtils.Join(Global.Settings.TUNTAP.DNS) : "1.1.1.1";
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.HijackDNS;
|
||||
else
|
||||
TUNTAPDNSTextBox.Text = "AioDNS";
|
||||
}
|
||||
@@ -297,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
|
||||
{
|
||||
@@ -305,29 +295,34 @@ 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(ComboBox control, Action<object> save, object[] values, object value, string propertyName = "SelectedItem")
|
||||
private void BindListComboBox<T>(ComboBox comboBox, Action<T> save, IEnumerable<T> values, T value) where T : notnull
|
||||
{
|
||||
if (control.DropDownStyle != ComboBoxStyle.DropDownList)
|
||||
if (comboBox.DropDownStyle != ComboBoxStyle.DropDownList)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
control.Items.AddRange(values);
|
||||
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).SelectedItem));
|
||||
Load += (_, _) => { control.SelectedItem = value; };
|
||||
var tagItems = values.Select(o => new TagItem<T>(o, o.ToString()!)).ToArray();
|
||||
comboBox.Items.AddRange(tagItems.Cast<object>().ToArray());
|
||||
|
||||
comboBox.ValueMember = nameof(TagItem<T>.Value);
|
||||
comboBox.DisplayMember = nameof(TagItem<T>.Text);
|
||||
|
||||
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>)((ComboBox)c).SelectedItem).Value));
|
||||
Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); };
|
||||
}
|
||||
|
||||
private void BindComboBox(ComboBox control, Func<string, bool> check, Action<string> save, string value, object[]? values = null)
|
||||
@@ -335,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,64 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -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,10 +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.Models;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -25,6 +27,22 @@ namespace Netch
|
||||
/// </summary>
|
||||
public static readonly List<Mode> Modes = new();
|
||||
|
||||
public static readonly string NetchDir;
|
||||
public static readonly string NetchExecutable;
|
||||
|
||||
static Global()
|
||||
{
|
||||
NetchExecutable = Application.ExecutablePath;
|
||||
NetchDir = Application.StartupPath;
|
||||
#if DEBUG
|
||||
Logger = new ConsoleLogger();
|
||||
#else
|
||||
Logger = new FileLogger();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 主窗体的静态实例
|
||||
/// </summary>
|
||||
@@ -36,8 +54,5 @@ namespace Netch
|
||||
IgnoreNullValues = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
||||
public static readonly string NetchDir = Application.StartupPath;
|
||||
public static readonly string NetchExecutable = Application.ExecutablePath;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IController
|
||||
{
|
||||
11
Netch/Interfaces/ILogger.cs
Normal file
11
Netch/Interfaces/ILogger.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface ILogger
|
||||
{
|
||||
void Info(string text);
|
||||
void Warning(string text);
|
||||
void Error(string text);
|
||||
void Debug(string s);
|
||||
void ShowLog();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
34
Netch/Interops/AioDNS.cs
Normal file
34
Netch/Interops/AioDNS.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
[DllImport(aiodns_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aiodns_dial(NameList name, byte[] value);
|
||||
|
||||
[DllImport(aiodns_bin, EntryPoint = "aiodns_init", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Init();
|
||||
|
||||
[DllImport(aiodns_bin, EntryPoint = "aiodns_free", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Free();
|
||||
|
||||
public enum NameList
|
||||
{
|
||||
TYPE_REST,
|
||||
TYPE_ADDR,
|
||||
TYPE_LIST,
|
||||
TYPE_CDNS,
|
||||
TYPE_ODNS
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Interops/NFAPI.cs
Normal file
15
Netch/Interops/NFAPI.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class NFAPI
|
||||
{
|
||||
private const string nfapinet_bin = "nfapinet.dll";
|
||||
|
||||
[DllImport(nfapinet_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_registerDriver(string driverName);
|
||||
|
||||
[DllImport(nfapinet_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_unRegisterDriver(string driverName);
|
||||
}
|
||||
}
|
||||
11
Netch/Interops/NF_STATUS.cs
Normal file
11
Netch/Interops/NF_STATUS.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public enum NF_STATUS : int
|
||||
{
|
||||
NF_STATUS_SUCCESS = 0,
|
||||
NF_STATUS_FAIL = -1,
|
||||
NF_STATUS_INVALID_ENDPOINT_ID = -2,
|
||||
NF_STATUS_NOT_INITIALIZED = -3,
|
||||
NF_STATUS_IO_ERROR = -4
|
||||
}
|
||||
}
|
||||
78
Netch/Interops/Redirector.cs
Normal file
78
Netch/Interops/Redirector.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class Redirector
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERICMP,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
|
||||
TYPE_CLRNAME,
|
||||
TYPE_ADDNAME,
|
||||
TYPE_BYPNAME,
|
||||
|
||||
TYPE_DNSHOST,
|
||||
|
||||
TYPE_TCPLISN,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
|
||||
TYPE_UDPLISN,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
}
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Global.Logger.Debug($"[Redirector] Dial {name}: {value}");
|
||||
return aio_dial(name, value);
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
{
|
||||
return aio_init();
|
||||
}
|
||||
|
||||
public static bool Free()
|
||||
{
|
||||
return aio_free();
|
||||
}
|
||||
|
||||
public const int UdpNameListOffset = (int)NameList.TYPE_UDPLISN - (int)NameList.TYPE_TCPLISN;
|
||||
|
||||
private const string Redirector_bin = "Redirector.bin";
|
||||
|
||||
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_dial(NameList name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_init();
|
||||
|
||||
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aio_free();
|
||||
|
||||
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getUP();
|
||||
|
||||
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong aio_getDL();
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
73
Netch/Interops/tun2socks.cs
Normal file
73
Netch/Interops/tun2socks.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class tun2socks
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
TYPE_BYPBIND,
|
||||
TYPE_BYPLIST,
|
||||
TYPE_DNSADDR,
|
||||
TYPE_ADAPMTU,
|
||||
TYPE_TCPREST,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
TYPE_UDPREST,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
}
|
||||
|
||||
public static bool Dial(NameList name, string 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();
|
||||
}
|
||||
|
||||
public static bool Free()
|
||||
{
|
||||
return tun_free();
|
||||
}
|
||||
|
||||
private const string tun2socks_bin = "tun2socks.bin";
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool tun_dial(NameList name, byte[] value);
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool tun_init();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool tun_free();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tun_luid();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong tun_getUP();
|
||||
|
||||
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ulong tun_getDL();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
@@ -8,25 +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)
|
||||
{
|
||||
var split = input.Split('-');
|
||||
var dotNetVersion = Version.Parse(split[0]);
|
||||
var preRelease = split.ElementAtOrDefault(1) ?? string.Empty;
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
return new SuffixVersion(dotNetVersion, preRelease);
|
||||
var strings = value.Split('-');
|
||||
|
||||
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);
|
||||
@@ -34,12 +63,11 @@ namespace Netch.Models.GitHubRelease
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
public int CompareTo(object? obj)
|
||||
{
|
||||
if (obj is not SuffixVersion version)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
@@ -59,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,12 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
public class VersionComparer : IComparer<object>
|
||||
{
|
||||
public int Compare(object x, object 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,15 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public interface IAdapter
|
||||
{
|
||||
public abstract int Index { get; }
|
||||
|
||||
public abstract IPAddress Gateway { get; }
|
||||
|
||||
public abstract NetworkInterface NetworkInterface { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace Netch.Models
|
||||
{
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR
|
||||
ERROR,
|
||||
DEBUG
|
||||
}
|
||||
}
|
||||
52
Netch/Models/Loggers/ConsoleLogger.cs
Normal file
52
Netch/Models/Loggers/ConsoleLogger.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Netch.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace Netch.Models.Loggers
|
||||
{
|
||||
public class ConsoleLogger : ILogger
|
||||
{
|
||||
public void Info(string text)
|
||||
{
|
||||
Write(text, LogLevel.INFO);
|
||||
}
|
||||
|
||||
public void Warning(string text)
|
||||
{
|
||||
Write(text, LogLevel.WARNING);
|
||||
}
|
||||
|
||||
public void Error(string text)
|
||||
{
|
||||
Write(text, LogLevel.ERROR);
|
||||
}
|
||||
|
||||
private void Write(string text, LogLevel logLevel)
|
||||
{
|
||||
var contents = $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Constants.EOF}";
|
||||
switch (logLevel)
|
||||
{
|
||||
case LogLevel.DEBUG:
|
||||
case LogLevel.INFO:
|
||||
case LogLevel.WARNING:
|
||||
Console.Write(contents);
|
||||
break;
|
||||
case LogLevel.ERROR:
|
||||
Console.Error.Write(contents);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void Debug(string s)
|
||||
{
|
||||
#if DEBUG
|
||||
Write(s, LogLevel.DEBUG);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ShowLog()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Netch/Models/Loggers/FileLogger.cs
Normal file
48
Netch/Models/Loggers/FileLogger.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Netch.Interfaces;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Netch.Models.Loggers
|
||||
{
|
||||
public class FileLogger : ILogger
|
||||
{
|
||||
public string LogFile { get; set; } = Path.Combine(Global.NetchDir, "logging\\application.log");
|
||||
|
||||
private readonly object _fileLock = new();
|
||||
|
||||
public void Info(string text)
|
||||
{
|
||||
Write(text, LogLevel.INFO);
|
||||
}
|
||||
|
||||
public void Warning(string text)
|
||||
{
|
||||
Write(text, LogLevel.WARNING);
|
||||
}
|
||||
|
||||
public void Error(string text)
|
||||
{
|
||||
Write(text, LogLevel.ERROR);
|
||||
}
|
||||
|
||||
public void Write(string text, LogLevel logLevel)
|
||||
{
|
||||
var contents = $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Constants.EOF}";
|
||||
|
||||
lock (_fileLock)
|
||||
File.AppendAllText(LogFile, contents);
|
||||
}
|
||||
|
||||
public void Debug(string s)
|
||||
{
|
||||
#if DEBUG
|
||||
Write(s, LogLevel.DEBUG);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ShowLog()
|
||||
{
|
||||
Utils.Utils.Open(LogFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Models/MessageException.cs
Normal file
15
Netch/Models/MessageException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class MessageException : Exception
|
||||
{
|
||||
public MessageException()
|
||||
{
|
||||
}
|
||||
|
||||
public MessageException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +1,129 @@
|
||||
using System;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class Mode
|
||||
{
|
||||
private readonly Lazy<List<string>> _lazyRule;
|
||||
|
||||
public string? FullName { get; private set; }
|
||||
|
||||
public Mode(string? fullName = default)
|
||||
/// <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;
|
||||
// TODO throw NotSupportedModeTypeException
|
||||
|
||||
var bypassChinaResult = int.TryParse(split.ElementAtOrDefault(2), out var bypassChina);
|
||||
BypassChina = this.ClientRouting() && bypassChinaResult && bypassChina == 1;
|
||||
(Remark, Type) = ReadHead(FullName);
|
||||
}
|
||||
|
||||
public string? FullName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 规则
|
||||
/// </summary>
|
||||
public List<string> Rule => _lazyRule.Value;
|
||||
public List<string> Content => _content ??= ReadContent();
|
||||
|
||||
/// <summary>
|
||||
/// 绕过中国(0. 不绕过 1. 绕过)
|
||||
/// </summary>
|
||||
public bool BypassChina { get; set; }
|
||||
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>
|
||||
@@ -152,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}, {(BypassChina ? 1 : 0)}{Constants.EOF}{string.Join(Constants.EOF, Rule)}";
|
||||
return $"[{(int)Type + 1}] {i18N.Translate(Remark)}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,13 +141,7 @@ namespace Netch.Models
|
||||
/// 是否会转发 UDP
|
||||
public static bool TestNatRequired(this Mode mode)
|
||||
{
|
||||
return mode.Type is 0 or 2;
|
||||
}
|
||||
|
||||
/// Socks5 分流是否能被有效实施
|
||||
public static bool ClientRouting(this Mode mode)
|
||||
{
|
||||
return mode.Type is not (1 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,69 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class OutboundAdapter : IAdapter
|
||||
{
|
||||
public OutboundAdapter(bool logging = true)
|
||||
{
|
||||
// 寻找出口适配器
|
||||
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);
|
||||
|
||||
Index = (int) pRoute.dwForwardIfIndex;
|
||||
Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
|
||||
_parametersRegistry =
|
||||
Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{NetworkInterface.Id}", true)!;
|
||||
|
||||
if (logging)
|
||||
{
|
||||
Logging.Info($"出口 网关 地址:{Gateway}");
|
||||
Logging.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public int Index { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
|
||||
|
||||
public string DNS
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return (string) _parametersRegistry.GetValue("NameServer");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
set => _parametersRegistry.SetValue("NameServer", value, RegistryValueKind.String);
|
||||
}
|
||||
|
||||
private readonly RegistryKey _parametersRegistry;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -49,7 +48,7 @@ namespace Netch.Models
|
||||
case bool b:
|
||||
return b ? $"{prefix}{key}" : null;
|
||||
default:
|
||||
if ((value?.ToString() ?? null).IsNullOrWhiteSpace())
|
||||
if (string.IsNullOrWhiteSpace(value?.ToString()))
|
||||
return p.IsDefined(typeof(OptionalAttribute)) ? null : throw new RequiredArgumentValueInvalidException(p.Name, this, null);
|
||||
|
||||
if (p.IsDefined(typeof(QuoteAttribute)))
|
||||
|
||||
@@ -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,12 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Utils;
|
||||
using Netch.Utils;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// TUN/TAP 适配器配置类
|
||||
/// </summary>
|
||||
public class TUNTAPConfig
|
||||
public class TUNConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 地址
|
||||
@@ -16,7 +16,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
public List<string> DNS { get; set; } = new();
|
||||
public string HijackDNS { get; set; } = "tcp://1.1.1.1:53";
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
@@ -36,12 +36,12 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 使用自定义 DNS 设置
|
||||
/// </summary>
|
||||
public bool UseCustomDNS { get; set; } = false;
|
||||
public bool UseCustomDNS { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 使用Fake DNS
|
||||
/// 全局绕过 IP 列表
|
||||
/// </summary>
|
||||
public bool UseFakeDNS { get; set; } = false;
|
||||
public List<string> BypassIPs { get; set; } = new();
|
||||
}
|
||||
|
||||
public class KcpConfig
|
||||
@@ -76,13 +76,43 @@ namespace Netch.Models
|
||||
|
||||
public class AioDNSConfig
|
||||
{
|
||||
public string ChinaDNS { get; set; } = "223.5.5.5";
|
||||
public string ChinaDNS { get; set; } = "tcp://223.5.5.5:53";
|
||||
|
||||
public string OtherDNS { get; set; } = "1.1.1.1";
|
||||
public string OtherDNS { get; set; } = "tcp://1.1.1.1:53";
|
||||
|
||||
public string Protocol { get; set; } = "tcp";
|
||||
public ushort ListenPort { get; set; } = 253;
|
||||
}
|
||||
|
||||
public string RulePath { get; set; } = "bin\\china_site_list";
|
||||
public class RedirectorConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public PortType ProxyProtocol { get; set; } = PortType.Both;
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启DNS转发
|
||||
/// </summary>
|
||||
public bool DNSHijack { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 转发DNS地址
|
||||
/// </summary>
|
||||
public string DNSHijackHost { get; set; } = "1.1.1.1:53";
|
||||
|
||||
public string ICMPHost { get; set; } = "1.2.4.8";
|
||||
|
||||
public bool ICMPHijack { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用RDR内置SS
|
||||
/// </summary>
|
||||
public bool RedirectorSS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否代理子进程
|
||||
/// </summary>
|
||||
public bool ChildProcessHandle { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,23 +120,15 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public class Setting
|
||||
{
|
||||
public RedirectorConfig Redirector { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 服务器列表
|
||||
/// </summary>
|
||||
public List<Server> Server { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// ACL规则
|
||||
/// </summary>
|
||||
public string ACL { get; set; } = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
|
||||
|
||||
public AioDNSConfig AioDNS { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 全局绕过 IP 列表
|
||||
/// </summary>
|
||||
public List<string> BypassIPs { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 是否检查 Beta 更新
|
||||
/// </summary>
|
||||
@@ -150,42 +172,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 模式选择位置
|
||||
/// </summary>
|
||||
public int ModeComboBoxSelectedIndex { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 转发DNS地址
|
||||
/// </summary>
|
||||
public string RedirectDNSAddr { get; set; } = "8.8.8.8";
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启DNS转发
|
||||
/// </summary>
|
||||
public bool RedirectDNS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 转发ICMP地址
|
||||
/// </summary>
|
||||
public string RedirectICMPAddr { get; set; } = "1.2.4.8";
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启ICMP转发
|
||||
/// </summary>
|
||||
public bool RedirectICMP { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// GFWList
|
||||
/// </summary>
|
||||
public string PAC { get; set; } = "https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac";
|
||||
|
||||
/// <summary>
|
||||
/// PAC端口
|
||||
/// </summary>
|
||||
public ushort Pac_Port { get; set; } = 2803;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public PortType ProcessProxyProtocol { get; set; } = PortType.Both;
|
||||
public int ModeComboBoxSelectedIndex { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 快捷配置数量
|
||||
@@ -202,21 +189,6 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public byte ProfileTableColumnCount { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用RDR内置SS
|
||||
/// </summary>
|
||||
public bool RedirectorSS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否代理子进程
|
||||
/// </summary>
|
||||
public bool ChildProcessHandle { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Redirector TCP 占用端口
|
||||
/// </summary>
|
||||
public ushort RedirectorTCPPort { get; set; } = 3901;
|
||||
|
||||
/// <summary>
|
||||
/// 网页请求超时 毫秒
|
||||
/// </summary>
|
||||
@@ -225,7 +197,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 解析服务器主机名
|
||||
/// </summary>
|
||||
public bool ResolveServerHostname { get; set; } = false;
|
||||
public bool ResolveServerHostname { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否开机启动软件
|
||||
@@ -235,7 +207,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 服务器选择位置
|
||||
/// </summary>
|
||||
public int ServerComboBoxSelectedIndex { get; set; } = 0;
|
||||
public int ServerComboBoxSelectedIndex { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器测试方式 false.ICMPing true.TCPing
|
||||
@@ -280,25 +252,24 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// TUNTAP 适配器配置
|
||||
/// </summary>
|
||||
public TUNTAPConfig TUNTAP { get; set; } = new();
|
||||
public TUNConfig TUNTAP { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 是否打开软件时更新订阅
|
||||
/// </summary>
|
||||
public bool UpdateServersWhenOpened { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用代理更新订阅
|
||||
/// </summary>
|
||||
public bool UseProxyToUpdateSubscription { get; set; } = false;
|
||||
|
||||
public V2rayConfig V2RayConfig { get; set; } = new();
|
||||
|
||||
public bool? AlwaysStartPACServer { get; set; }
|
||||
|
||||
public Setting Clone()
|
||||
{
|
||||
return (Setting) MemberwiseClone();
|
||||
return (Setting)MemberwiseClone();
|
||||
}
|
||||
|
||||
public void Set(Setting value)
|
||||
{
|
||||
foreach (var p in typeof(Setting).GetProperties())
|
||||
p.SetValue(this, p.GetValue(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Netch.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
|
||||
19
Netch/Models/TagItem.cs
Normal file
19
Netch/Models/TagItem.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
internal class TagItem<T>
|
||||
{
|
||||
private readonly string _text;
|
||||
|
||||
public TagItem(T value, string text)
|
||||
{
|
||||
_text = text;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Text => i18N.Translate(_text);
|
||||
|
||||
public T Value { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class TapAdapter : IAdapter
|
||||
{
|
||||
public TapAdapter()
|
||||
{
|
||||
Index = -1;
|
||||
ComponentID = TUNTAP.GetComponentID() ?? throw new MessageException("TAP 适配器未安装");
|
||||
|
||||
// 根据 ComponentID 寻找 Tap适配器
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.Id == ComponentID);
|
||||
Index = NetworkInterface.GetIPProperties().GetIPv4Properties().Index;
|
||||
Logging.Info($"TAP 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}");
|
||||
}
|
||||
|
||||
public string ComponentID { get; }
|
||||
|
||||
public int Index { get; }
|
||||
|
||||
public IPAddress Gateway => IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,37 +4,7 @@ namespace Netch
|
||||
{
|
||||
public static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建路由规则
|
||||
/// </summary>
|
||||
/// <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(string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 删除路由规则
|
||||
/// </summary>
|
||||
/// <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(string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint FlushDNSResolverCache();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
public static extern uint RefreshDNSCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
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
|
||||
{
|
||||
@@ -15,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
|
||||
AttachConsole();
|
||||
#else
|
||||
if (args.Contains(Constants.Parameter.Console))
|
||||
AttachConsole();
|
||||
ConsoleHwnd = GetConsoleWindow();
|
||||
#if RELEASE
|
||||
User32.ShowWindow(ConsoleHwnd, ShowWindowCommand.SW_HIDE);
|
||||
#endif
|
||||
|
||||
if (args.Contains(Constants.Parameter.ForceUpdate))
|
||||
@@ -33,14 +36,14 @@ namespace Netch
|
||||
|
||||
// 设置当前目录
|
||||
Directory.SetCurrentDirectory(Global.NetchDir);
|
||||
Environment.SetEnvironmentVariable("PATH",
|
||||
Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ";" + Path.Combine(Global.NetchDir, "bin"),
|
||||
EnvironmentVariableTarget.Process);
|
||||
var binPath = Path.Combine(Global.NetchDir, "bin");
|
||||
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);
|
||||
@@ -79,28 +82,23 @@ namespace Netch
|
||||
Environment.Exit(2);
|
||||
}
|
||||
|
||||
Logging.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Task.Run(() => { Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); });
|
||||
Global.Logger.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Task.Run(() => { Global.Logger.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); });
|
||||
|
||||
// 绑定错误捕获
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
Application.ThreadException += Application_OnException;
|
||||
|
||||
Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(Global.MainForm);
|
||||
}
|
||||
|
||||
private static void AttachConsole()
|
||||
{
|
||||
if (!NativeMethods.AttachConsole(-1))
|
||||
NativeMethods.AllocConsole();
|
||||
}
|
||||
|
||||
public static void Application_OnException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
Logging.Error(e.Exception.ToString());
|
||||
Utils.Utils.Open(Logging.LogFile);
|
||||
Global.Logger.Error(e.Exception.ToString());
|
||||
Global.Logger.ShowLog();
|
||||
}
|
||||
|
||||
private static void SingleInstance_ArgumentsReceived(IEnumerable<string> args)
|
||||
|
||||
@@ -1,94 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<StartupObject>Netch.Netch</StartupObject>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
<ApplicationIcon>Resources\Netch.ico</ApplicationIcon>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
<AnalysisMode>Default</AnalysisMode>
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>x64</Platforms>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- <EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>-->
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<NoWarn />
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn />
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove=".gitignore" />
|
||||
</ItemGroup>
|
||||
|
||||
<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.Win32.Registry" Version="5.0.0" />
|
||||
<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.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.1" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.9.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.7" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.7" />
|
||||
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
|
||||
<PackageReference Include="WindowsProxy" Version="5.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<!-- .NET Framework -->
|
||||
<PackageReference Include="ILMerge" Version="3.0.41" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Web" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' != 'net'">
|
||||
<!-- .NET Core -->
|
||||
<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.9" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<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>
|
||||
<ProjectReference Include="..\Interop.nfapinet\Interop.nfapinet.csproj" />
|
||||
<ProjectReference Include="..\SearchComboBox\SearchComboBox.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Visible="false" Include="..\binaries\**" LinkBase="bin" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
|
||||
<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,9 +66,7 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Forms\Mode\Route.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\Mode\Route.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -110,7 +74,6 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Remove="Forms\LogForm.resx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -119,14 +82,6 @@
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="set TargetFramework=$(TargetFramework)
set Configuration=$(Configuration)
set ILMergeConsolePath=$(ILMergeConsolePath)
set TargetDir=$(TargetDir)
set SolutionDir=$(SolutionDir)
call $(ProjectDir)PostBuild.bat" />
|
||||
</Target>
|
||||
|
||||
<Target Condition="'$(PublishSingleFile)' == 'true'" AfterTargets="_ComputeFilesToBundle" Name="RemoveDupeAssemblies">
|
||||
<ItemGroup>
|
||||
@@ -135,5 +90,4 @@
|
||||
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\TraceReloggerLib.dll" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
if %Configuration%==Release if %TargetFramework%==net48 (
|
||||
:: Merge dlls
|
||||
%ILMergeConsolePath% /wildcards /out:%TargetDir%Netch.exe ^
|
||||
/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" ^
|
||||
/targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8" ^
|
||||
%TargetDir%Netch.exe ^
|
||||
%TargetDir%*.dll
|
||||
|
||||
DEL /f %TargetDir%*.dll >NUL 2>&1
|
||||
)
|
||||
|
||||
if %Configuration%==Release (
|
||||
DEL /f %TargetDir%*.config >NUL 2>&1
|
||||
DEL /f %TargetDir%*.pdb >NUL 2>&1
|
||||
)
|
||||
|
||||
RD /s /Q %TargetDir%x86 >NUL 2>&1
|
||||
RD /s /Q %TargetDir%de %TargetDir%es %TargetDir%fr %TargetDir%it %TargetDir%pl %TargetDir%ru %TargetDir%zh-CN >NUL 2>&1
|
||||
|
||||
exit 0
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
using Netch.Controllers;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Netch.Controllers;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"Information": "信息",
|
||||
"Error": "错误",
|
||||
|
||||
"If this is your first time using this software,\n please check https://netch.org to install supports first,\n or the program may report errors.": "如果你是第一次使用本软件,\n请务必前往 https://netch.org 安装程序所需依赖,\n否则程序将无法正常运行!",
|
||||
"Missing File or runtime components": "缺少文件或运行库",
|
||||
"Please extract all files then run the program!": "请先解压所有文件再执行程序!",
|
||||
|
||||
@@ -16,11 +15,10 @@
|
||||
"Stopping": "正在停止中",
|
||||
"Stopped": "已停止",
|
||||
"Starting {0}": "正在启动 {0}",
|
||||
"Starting NatTester": "正在启动 NAT 测试",
|
||||
"SetupBypass": "设置绕行规则",
|
||||
"Testing NAT": "正在测试 NAT",
|
||||
"Setup Route Table Rule": "配置路由规则",
|
||||
"Test failed": "测试失败",
|
||||
"Starting update subscription": "正在更新订阅",
|
||||
"Starting update ACL": "正在更新 ACL",
|
||||
"Subscription updated": "订阅更新完毕",
|
||||
"Register driver": "正在注册驱动",
|
||||
|
||||
@@ -67,7 +65,6 @@
|
||||
"Subscribe": "订阅",
|
||||
"Manage Subscribe Links": "管理订阅链接",
|
||||
"Update Servers From Subscribe Links": "从订阅链接更新服务器",
|
||||
"Update Servers From Subscribe Links With Proxy": "使用代理从订阅链接更新服务器",
|
||||
"No subscription link": "没有任何一条订阅链接",
|
||||
"Updating {0}": "正在更新 {0}",
|
||||
"Update {1} server(s) from {0}": "从 {0} 更新 {1} 个服务器",
|
||||
@@ -85,22 +82,12 @@
|
||||
"Uninstall {0}": "卸载 {0}",
|
||||
"Uninstalling {0}": "正在卸载 {0} 中",
|
||||
"{0} has been uninstalled": "{0} 已卸载",
|
||||
"Reload Modes": "重载模式",
|
||||
"Modes have been reload": "模式已重载",
|
||||
"Clean DNS Cache": "清理 DNS 缓存",
|
||||
"DNS cache cleanup succeeded": "DNS 缓存清理成功",
|
||||
"Remove Netch Firewall Rules": "移除 Netch 防火墙规则",
|
||||
|
||||
"Update PAC": "更新 PAC",
|
||||
"PAC updated successfully": "PAC 更新成功",
|
||||
"PAC update failed": "PAC 更新失败",
|
||||
|
||||
"Update ACL": "更新 ACL 规则",
|
||||
"Update ACL with proxy": "使用代理更新 ACL 规则",
|
||||
"ACL updated successfully": "ACL 更新成功",
|
||||
"ACL update failed": "ACL 更新失败",
|
||||
|
||||
"Open Directory": "打开目录",
|
||||
"Show/Hide Console": "显示/隐藏控制台",
|
||||
|
||||
"About": "关于",
|
||||
"FAQ": "常见问题",
|
||||
@@ -155,25 +142,21 @@
|
||||
"Gateway": "网关",
|
||||
"Use Custom DNS": "使用自定义 DNS",
|
||||
"Proxy DNS in Proxy Rule IPs Mode": "在 代理规则IP 模式下代理 DNS",
|
||||
"Use Fake DNS": "使用 Fake DNS",
|
||||
"Exit when closed": "关闭时退出",
|
||||
"Stop when exited": "退出时停止",
|
||||
"Global Bypass IPs": "全局直连 IP",
|
||||
"Check update when opened": "打开软件时检查更新",
|
||||
"Check Beta update": "检查 Beta 更新",
|
||||
"Update Servers when opened": "打开软件时更新服务器",
|
||||
"SS DLL": "SS DLL",
|
||||
"Modify System DNS": "修改系统 DNS",
|
||||
"Proxy Protocol": "代理协议",
|
||||
"DNS Redirector": "DNS转发",
|
||||
"ICMP Redirector": "ICMP转发",
|
||||
"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 服务器",
|
||||
"Custom ACL": "自定义 ACL 规则",
|
||||
"Language": "语言",
|
||||
"Resolve Server Hostname": "解析服务器主机名",
|
||||
"FullCone Support (Required Server Xray-core v1.3.0+)": "FullCone 支持(需服务端 Xray-core v1.3.0+)",
|
||||
@@ -186,12 +169,5 @@
|
||||
"Exit": "退出",
|
||||
|
||||
"The {0} port is in use.": "{0} 端口已被占用",
|
||||
"The {0} port is reserved by system.": "{0} 端口是系统保留端口",
|
||||
|
||||
"[Web Proxy] Bypass LAN": "[网页代理] 绕过局域网",
|
||||
"[Non Web Proxy] Bypass LAN": "[不设置代理] 绕过局域网",
|
||||
"[TUN/TAP] Bypass LAN": "[TUN/TAP] 绕过局域网",
|
||||
"[Web Proxy] Bypass LAN and China": "[网页代理] 绕过局域网和中国大陆",
|
||||
"[Non Web Proxy] Bypass LAN and China": "[不设置代理] 绕过局域网和中国大陆",
|
||||
"[TUN/TAP] Bypass LAN and China": "[TUN/TAP] 绕过局域网和中国大陆"
|
||||
"The {0} port is reserved by system.": "{0} 端口是系统保留端口"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
@@ -10,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";
|
||||
|
||||
@@ -22,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
|
||||
{
|
||||
@@ -37,9 +36,6 @@ namespace Netch.Servers.Shadowsocks
|
||||
plugin_opts = server.PluginOption
|
||||
};
|
||||
|
||||
if (mode.BypassChina)
|
||||
command.acl = $"{Path.GetFullPath(File.Exists(Constants.UserACL) ? Constants.UserACL : Constants.BuiltinACL)}";
|
||||
|
||||
StartInstanceAuto(command.ToString());
|
||||
}
|
||||
|
||||
|
||||
@@ -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,10 +62,10 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
var server = (Shadowsocks)s;
|
||||
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
Global.Logger.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -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,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
@@ -10,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";
|
||||
|
||||
@@ -22,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
|
||||
{
|
||||
@@ -40,9 +39,6 @@ namespace Netch.Servers.ShadowsocksR
|
||||
u = true
|
||||
};
|
||||
|
||||
if (mode.BypassChina)
|
||||
command.acl = $"{Path.GetFullPath(File.Exists(Constants.UserACL) ? Constants.UserACL : Constants.BuiltinACL)}";
|
||||
|
||||
StartInstanceAuto(command.ToString());
|
||||
}
|
||||
|
||||
|
||||
@@ -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,22 +143,22 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
var server = (ShadowsocksR)s;
|
||||
if (!SSRGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}");
|
||||
Global.Logger.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSRGlobal.Protocols.Contains(server.Protocol))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 协议:{server.Protocol}");
|
||||
Global.Logger.Error($"不支持的 SSR 协议:{server.Protocol}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSRGlobal.OBFSs.Contains(server.OBFS))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 混淆:{server.OBFS}");
|
||||
Global.Logger.Error($"不支持的 SSR 混淆:{server.OBFS}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user