mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d535aa27e | ||
|
|
03c3c151bf | ||
|
|
7a3b5ff487 | ||
|
|
598ff19535 | ||
|
|
d02135f31b | ||
|
|
a7756dabc1 | ||
|
|
7ce1127006 | ||
|
|
fec84a4952 | ||
|
|
d335c69fab | ||
|
|
1228a565c1 | ||
|
|
dc904c9c0b | ||
|
|
d829e347d3 | ||
|
|
a01761d2e2 | ||
|
|
68d87e2ff2 | ||
|
|
04d6933319 | ||
|
|
e46eef17d0 | ||
|
|
d3c3958dab | ||
|
|
5ec8d38fd1 | ||
|
|
2a8754ecfb | ||
|
|
cbc6822bff | ||
|
|
96bd7473ca | ||
|
|
54b2b87dec | ||
|
|
42baed8b8f | ||
|
|
f68aae6795 | ||
|
|
8e2008077d | ||
|
|
5b4f0026ff | ||
|
|
89f9dccb87 | ||
|
|
3e377f2e9d | ||
|
|
635212f24d | ||
|
|
46d60babbc | ||
|
|
8f80f9abef | ||
|
|
e268f1838f | ||
|
|
d99229ad50 | ||
|
|
df85d5797d | ||
|
|
74856ccd61 | ||
|
|
0165d080c6 | ||
|
|
97fb20e326 | ||
|
|
4d71e2d12f | ||
|
|
0fa83eac3c | ||
|
|
aa6623b063 | ||
|
|
94335ad900 | ||
|
|
baf3b39dd3 | ||
|
|
c12122f7d0 | ||
|
|
3e5a4fc102 | ||
|
|
57dbd0193a | ||
|
|
5647a6c7ea | ||
|
|
773bad4845 | ||
|
|
3e943ec6b8 | ||
|
|
920b068a1e | ||
|
|
7eac7b0837 | ||
|
|
e1f3390787 | ||
|
|
a62f694908 | ||
|
|
98f3218e28 | ||
|
|
9da801dc19 | ||
|
|
ff7ae73156 | ||
|
|
6810bcc87f | ||
|
|
3462a3badf | ||
|
|
87a3581dff | ||
|
|
060c42efbc | ||
|
|
72ae9b7bf3 | ||
|
|
bf4b637940 | ||
|
|
f8b1c4acd6 | ||
|
|
88f3a4940b | ||
|
|
cb8dc2163f | ||
|
|
ee206f3df0 | ||
|
|
d5e1ef1a56 | ||
|
|
aeaef4e125 | ||
|
|
352602a7ed | ||
|
|
20d4682d40 | ||
|
|
6ddffcbca4 | ||
|
|
47faf6be88 | ||
|
|
71028fd6a9 | ||
|
|
a03991ddb9 | ||
|
|
414a43b719 | ||
|
|
32f8d15f86 | ||
|
|
5eb68359d3 | ||
|
|
958c28c695 | ||
|
|
320b1f66c9 | ||
|
|
7015784e4f | ||
|
|
64071721d8 | ||
|
|
e3b1ae0621 | ||
|
|
4836e4c913 | ||
|
|
a70b557e0c | ||
|
|
1b19c12824 | ||
|
|
35be8bedd0 | ||
|
|
5109134843 | ||
|
|
573b5179bb | ||
|
|
8c03f7c6db | ||
|
|
7d7c91bc68 | ||
|
|
5ed3f8e073 | ||
|
|
7636b0ed27 | ||
|
|
29b003bacd | ||
|
|
c0452552ec | ||
|
|
3aee365b48 | ||
|
|
58c5f9d086 | ||
|
|
62dc9166ce | ||
|
|
e7d04e36ac | ||
|
|
8357878b68 | ||
|
|
f5da527775 | ||
|
|
9f7fd9020f | ||
|
|
6f87280d57 | ||
|
|
76f7c987ac | ||
|
|
ff985b14a8 | ||
|
|
951cee1c06 | ||
|
|
d31617b65c | ||
|
|
80be24120b | ||
|
|
4676de32b9 | ||
|
|
1775b35513 | ||
|
|
80a92a401c | ||
|
|
b53ea1f7e4 | ||
|
|
486fa195e7 | ||
|
|
2d000f5f4f | ||
|
|
8a48e321b5 | ||
|
|
34acb6b281 | ||
|
|
5bbef8db12 | ||
|
|
4fba66fab8 | ||
|
|
6827207434 | ||
|
|
d8e60aa355 | ||
|
|
f3a7b7cf57 | ||
|
|
26fe7ad593 | ||
|
|
7493f07da9 | ||
|
|
f6dfb25e3f | ||
|
|
1e5d357f34 | ||
|
|
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 |
@@ -12,6 +12,7 @@ tab_width = 4
|
||||
# Microsoft .NET properties
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
|
||||
csharp_space_after_cast = false
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
@@ -27,7 +28,7 @@ dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
# ReSharper properties
|
||||
resharper_align_multiline_switch_expression = true
|
||||
resharper_align_multiline_switch_expression = false
|
||||
resharper_align_multline_type_parameter_constrains = true
|
||||
resharper_blank_lines_after_block_statements = 0
|
||||
resharper_blank_lines_after_multiline_statements = 1
|
||||
@@ -73,7 +74,7 @@ resharper_place_simple_initializer_on_single_line = true
|
||||
resharper_place_simple_switch_expression_on_single_line = true
|
||||
resharper_show_autodetect_configure_formatting_tip = false
|
||||
resharper_space_around_arrow_op = true
|
||||
resharper_space_within_single_line_array_initializer_braces = false
|
||||
resharper_space_within_single_line_array_initializer_braces = true
|
||||
resharper_use_indent_from_vs = false
|
||||
resharper_wrap_array_initializer_style = wrap_if_long
|
||||
resharper_wrap_before_arrow_with_expressions = true
|
||||
|
||||
32
.github/ISSUE_TEMPLATE/bug_report.md.off
vendored
32
.github/ISSUE_TEMPLATE/bug_report.md.off
vendored
@@ -1,32 +0,0 @@
|
||||
---
|
||||
name: 'Bug report'
|
||||
about: 'Create a report to help us improve'
|
||||
title: ''
|
||||
labels: '需要核实'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Open Netch
|
||||
2. ...
|
||||
|
||||
**Log**
|
||||
Attaching any log files in the folder `Netch\logging` is strongly recommended.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
- OS: [e.g. Windows 10 Pro 64-bit 1903]
|
||||
- Netch Version: [e.g. 1.0.0-STABLE.x64]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
28
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
28
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,12 +1,7 @@
|
||||
name: Bug report
|
||||
description: "Create a report to help us improve"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
description: Create a report to help us improve
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**"
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
@@ -19,7 +14,6 @@ body:
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
placeholder: |
|
||||
Steps to reproduce the behavior:
|
||||
1. Open Netch
|
||||
2. ...
|
||||
validations:
|
||||
@@ -30,26 +24,28 @@ body:
|
||||
label: CAPTCHA
|
||||
description: Please confirm the options below.
|
||||
options:
|
||||
- label: I am human
|
||||
- label: Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
render: shell
|
||||
label: Log
|
||||
description: Attaching any log files in the folder `Netch\logging` is strongly recommended.
|
||||
description: Attaching any log files in the folder `logging` is strongly recommended.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
render: txt
|
||||
placeholder: |
|
||||
- OS: [e.g. Windows 10 Pro 64-bit 1903]
|
||||
- Netch Version: [e.g. 1.0.0-STABLE.x64]
|
||||
- OS: [e.g. Windows 10 x64 Professional Workstation 20H2 19042.928]
|
||||
- Netch Version: [e.g. 1.0.0]
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
value: |
|
||||
In the text box below, you can attach any relevant screenshots and files.
|
||||
label: Additional information
|
||||
description: >
|
||||
If you have any additional information for us, use the field below.
|
||||
|
||||
29
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md.off
vendored
29
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md.off
vendored
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: '错误报告'
|
||||
about: '创建错误报告以帮助我们改进'
|
||||
title: ''
|
||||
labels: '需要核实'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
|
||||
|
||||
**错误描述**
|
||||
对错误的清晰简洁描述
|
||||
|
||||
**复现步骤**
|
||||
1. 打开 Netch 软件
|
||||
2. ...
|
||||
|
||||
**日志**
|
||||
强烈建议附上任何在 `Netch\logging` 文件夹下面的日志。
|
||||
|
||||
**错误截图**
|
||||
如果适用,请添加屏幕截图以帮助解释您的问题
|
||||
|
||||
**信息**
|
||||
- 操作系统:[例如 Windows 10 专业版 64 位 1903]
|
||||
- 软件版本:[例如 1.0.0-STABLE 64 位]
|
||||
|
||||
**额外信息**
|
||||
35
.github/ISSUE_TEMPLATE/bug_report.zh-CN.yml
vendored
35
.github/ISSUE_TEMPLATE/bug_report.zh-CN.yml
vendored
@@ -1,54 +1,43 @@
|
||||
name: 错误报告
|
||||
description: "创建错误报告以帮助我们改进"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
description: 创建错误报告以帮助我们改进
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**"
|
||||
- type: textarea
|
||||
id: error
|
||||
attributes:
|
||||
label: "错误描述"
|
||||
label: 错误描述
|
||||
description: 对错误的清晰简洁描述
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: "复现步骤"
|
||||
label: 复现步骤
|
||||
placeholder: |
|
||||
1. 打开 Netch 软件
|
||||
2. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: captcha
|
||||
attributes:
|
||||
label: 验证
|
||||
description: 请确认下面选项
|
||||
options:
|
||||
- label: 我是人类
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
render: shell
|
||||
label: 日志
|
||||
description: 强烈建议附上任何在 `Netch\logging` 文件夹下面的日志
|
||||
description: 强烈建议附上任何在 `logging` 文件夹下面的日志
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: 操作环境
|
||||
render: txt
|
||||
placeholder: |
|
||||
操作系统:[Windows 10 专业版 64 位 1903]
|
||||
软件版本:[1.0.0-STABLE 64 位]
|
||||
操作系统:[Windows 10 x64 Professional Workstation 20H2 19042.928]
|
||||
软件版本:[1.0.0]
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
value: |
|
||||
label: 额外信息
|
||||
description: >
|
||||
下面的文本框中你可以附上跟 issue 相关的截图、文件
|
||||
|
||||
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,9 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Telegram Channel
|
||||
url: https://t.me/Netch
|
||||
url: https://t.me/netch_channel
|
||||
about: Telegram Channel
|
||||
|
||||
- name: Telegram Group
|
||||
url: https://t.me/Netch_Discuss_Group
|
||||
about: Telegram Group
|
||||
url: https://t.me/netch_group
|
||||
about: Telegram Group
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/feature_request.md.off
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md.off
vendored
@@ -1,16 +0,0 @@
|
||||
---
|
||||
name: 'Feature request'
|
||||
about: 'Suggest an idea for this project'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
|
||||
|
||||
**Describe the feature you want**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Additional context** (Optional)
|
||||
Add any other context or screenshots about the feature request here.
|
||||
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,16 +1,11 @@
|
||||
name: request
|
||||
description: "Suggest an idea for this project"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
name: Feature request
|
||||
description: Suggest an idea for this project
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "Describe the feature you want"
|
||||
label: Describe the feature you want
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
name: '功能请求'
|
||||
about: '建议这个项目的想法'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
|
||||
|
||||
**功能描述**
|
||||
简明扼要地描述需要的功能
|
||||
|
||||
**额外信息**
|
||||
11
.github/ISSUE_TEMPLATE/feature_request.zh-CN.yml
vendored
11
.github/ISSUE_TEMPLATE/feature_request.zh-CN.yml
vendored
@@ -1,16 +1,11 @@
|
||||
name: 功能请求
|
||||
description: "建议这个项目的想法"
|
||||
title: ""
|
||||
labels: 需要核实
|
||||
issue_body: true
|
||||
description: 建议这个项目的想法
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: "功能描述"
|
||||
label: 功能描述
|
||||
description: 简明扼要地描述需要的功能
|
||||
validations:
|
||||
required: true
|
||||
|
||||
27
.github/dependabot.yml
vendored
27
.github/dependabot.yml
vendored
@@ -1,34 +1,21 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "07:00"
|
||||
time: "00:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- "automatic"
|
||||
open-pull-requests-limit: 114514
|
||||
|
||||
- package-ecosystem: "nuget"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "07:15"
|
||||
time: "00:10"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "07:15"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "Automatic"
|
||||
open-pull-requests-limit: 99
|
||||
- "automatic"
|
||||
open-pull-requests-limit: 114514
|
||||
|
||||
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@@ -1,5 +1,8 @@
|
||||
name: Netch Build CI
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -40,7 +40,12 @@ jobs:
|
||||
files: |
|
||||
Netch.7z
|
||||
body: |
|
||||
[](https://t.me/Netch) [](https://t.me/Netch_Discuss_Group)
|
||||
[](https://t.me/netch_channel) [](https://t.me/netch_group)
|
||||
|
||||
[**第一次使用请务必先安装 .NET 5.0 运行库**](https://aka.ms/dotnet/5.0/windowsdesktop-runtime-win-x64.exe)
|
||||
|
||||
## Changelogs
|
||||
* This is an automated deployment of GitHub Actions, the change log should be updated manually soon
|
||||
|
||||
## 更新日志
|
||||
* 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新
|
||||
|
||||
20
Netch.sln
20
Netch.sln
@@ -1,10 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29009.5
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31423.177
|
||||
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}") = "UnitTest", "UnitTest\UnitTest.csproj", "{38240783-9AD2-4A01-84C1-1A3E5F05720F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AdditionalFiles", "AdditionalFiles", "{B7354F81-F79C-4C23-9067-C4DAE91B56F0}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.gitignore = .gitignore
|
||||
common.props = common.props
|
||||
global.json = global.json
|
||||
LICENSE = LICENSE
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -15,6 +27,10 @@ Global
|
||||
{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
|
||||
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Debug|x64.Build.0 = Debug|x64
|
||||
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Release|x64.ActiveCfg = Release|x64
|
||||
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -2,13 +2,26 @@
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public const string TempConfig = "data\\last.json";
|
||||
public const string TempRouteFile = "data\\route.txt";
|
||||
|
||||
public const string AioDnsRuleFile = "bin\\aiodns.conf";
|
||||
public const string NFDriver = "bin\\nfdriver.sys";
|
||||
public const string STUNServersFile = "bin\\stun.txt";
|
||||
|
||||
public const string LogFile = "logging\\application.log";
|
||||
|
||||
public const string OutputTemplate = @"[{Timestamp:yyyy-MM-dd HH:mm:ss}][{Level}] {Message:lj}{NewLine}{Exception}";
|
||||
public const string EOF = "\r\n";
|
||||
|
||||
public const string DefaultGroup = "NONE";
|
||||
|
||||
public static class Parameter
|
||||
{
|
||||
public const string Show = "-show";
|
||||
public const string ForceUpdate = "-forceUpdate";
|
||||
public const string Console = "-console";
|
||||
}
|
||||
|
||||
public const string WintunDllFile = "bin\\wintun.dll";
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,35 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using static Netch.Interops.AioDNSInterops;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using static Netch.Interops.AioDNS;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class DNSController : IController
|
||||
{
|
||||
public string Name { get; } = "DNS Service";
|
||||
public string Name => "DNS Service";
|
||||
|
||||
public void Stop()
|
||||
public async Task StopAsync()
|
||||
{
|
||||
Free();
|
||||
await FreeAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动DNS服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void Start()
|
||||
public async Task StartAsync()
|
||||
{
|
||||
Dial(NameList.TYPE_REST, "");
|
||||
Dial(NameList.TYPE_ADDR, $"{Global.Settings.LocalAddress}:{Global.Settings.AioDNS.ListenPort}");
|
||||
Dial(NameList.TYPE_LIST, Path.GetFullPath(Global.Settings.AioDNS.RulePath));
|
||||
Dial(NameList.TYPE_CDNS, $"{Global.Settings.AioDNS.ChinaDNS}");
|
||||
Dial(NameList.TYPE_ODNS, $"{Global.Settings.AioDNS.OtherDNS}");
|
||||
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
|
||||
|
||||
if (!Init())
|
||||
throw new Exception("AioDNS start failed");
|
||||
var aioDnsConfig = Global.Settings.AioDNS;
|
||||
var listenAddress = Global.Settings.LocalAddress;
|
||||
|
||||
Dial(NameList.TYPE_REST, "");
|
||||
Dial(NameList.TYPE_ADDR, $"{listenAddress}:{aioDnsConfig.ListenPort}");
|
||||
Dial(NameList.TYPE_LIST, Path.GetFullPath(Constants.AioDnsRuleFile));
|
||||
Dial(NameList.TYPE_CDNS, $"{aioDnsConfig.ChinaDNS}");
|
||||
Dial(NameList.TYPE_ODNS, $"{aioDnsConfig.OtherDNS}");
|
||||
|
||||
if (!await InitAsync())
|
||||
throw new Exception("AioDNS start failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +1,163 @@
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Timer = System.Timers.Timer;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Netch.Enums;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public abstract class Guard
|
||||
{
|
||||
private readonly Timer _flushFileStreamTimer = new(300) { AutoReset = true };
|
||||
|
||||
private FileStream? _logFileStream;
|
||||
|
||||
private StreamWriter? _logStreamWriter;
|
||||
private bool _redirectToFile = true;
|
||||
|
||||
/// <summary>
|
||||
/// 日志文件(重定向输出文件)
|
||||
/// </summary>
|
||||
/// <param name="mainFile">application path relative of Netch\bin</param>
|
||||
/// <param name="redirectOutput"></param>
|
||||
/// <param name="encoding">application output encode</param>
|
||||
protected Guard(string mainFile, bool redirectOutput = true, Encoding? encoding = null)
|
||||
{
|
||||
RedirectOutput = redirectOutput;
|
||||
|
||||
var fileName = Path.GetFullPath($"bin\\{mainFile}");
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
throw new MessageException(i18N.Translate($"bin\\{mainFile} file not found!"));
|
||||
|
||||
Instance = new Process
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
FileName = fileName,
|
||||
WorkingDirectory = $"{Global.NetchDir}\\bin",
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = !RedirectOutput,
|
||||
RedirectStandardOutput = RedirectOutput,
|
||||
StandardOutputEncoding = RedirectOutput ? encoding : null,
|
||||
RedirectStandardError = RedirectOutput,
|
||||
StandardErrorEncoding = RedirectOutput ? encoding : null,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected string LogPath => Path.Combine(Global.NetchDir, $"logging\\{Name}.log");
|
||||
|
||||
/// <summary>
|
||||
/// 成功启动关键词
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<string> StartedKeywords { get; set; } = new List<string>();
|
||||
protected virtual IEnumerable<string> StartedKeywords { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 启动失败关键词
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<string> StoppedKeywords { get; set; } = new List<string>();
|
||||
protected virtual IEnumerable<string> FailedKeywords { get; } = new List<string>();
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 主程序名
|
||||
/// </summary>
|
||||
public abstract string MainFile { get; protected set; }
|
||||
private State State { get; set; } = State.Waiting;
|
||||
|
||||
protected State State { get; set; } = State.Waiting;
|
||||
private bool RedirectOutput { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 进程是否可以重定向输出
|
||||
/// </summary>
|
||||
protected bool RedirectStd { get; set; } = true;
|
||||
public Process Instance { get; }
|
||||
|
||||
protected bool RedirectToFile
|
||||
~Guard()
|
||||
{
|
||||
get => RedirectStd && _redirectToFile;
|
||||
set => _redirectToFile = value;
|
||||
_logFileStream?.Dispose();
|
||||
_logStreamWriter?.Dispose();
|
||||
Instance.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 进程实例
|
||||
/// </summary>
|
||||
public Process? Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序输出的编码,
|
||||
/// </summary>
|
||||
protected virtual Encoding? InstanceOutputEncoding { get; } = null;
|
||||
|
||||
public abstract void Stop();
|
||||
|
||||
/// <summary>
|
||||
/// 停止进程
|
||||
/// </summary>
|
||||
protected void StopInstance()
|
||||
protected async Task StartGuardAsync(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
|
||||
{
|
||||
State = State.Starting;
|
||||
|
||||
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
_logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true };
|
||||
|
||||
Instance.StartInfo.Arguments = argument;
|
||||
Instance.Start();
|
||||
|
||||
if (priority != ProcessPriorityClass.Normal)
|
||||
Instance.PriorityClass = priority;
|
||||
|
||||
if (RedirectOutput)
|
||||
{
|
||||
Task.Run(() => ReadOutput(Instance.StandardOutput)).Forget();
|
||||
Task.Run(() => ReadOutput(Instance.StandardError)).Forget();
|
||||
|
||||
if (!StartedKeywords.Any())
|
||||
{
|
||||
// Skip, No started keyword
|
||||
State = State.Started;
|
||||
return;
|
||||
}
|
||||
|
||||
// wait ReadOutput change State
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
await Task.Delay(50);
|
||||
switch (State)
|
||||
{
|
||||
case State.Started:
|
||||
OnStarted();
|
||||
return;
|
||||
case State.Stopped:
|
||||
await StopGuardAsync();
|
||||
OnStartFailed();
|
||||
throw new MessageException($"{Name} 控制器启动失败");
|
||||
}
|
||||
}
|
||||
|
||||
await StopGuardAsync();
|
||||
throw new MessageException($"{Name} 控制器启动超时");
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadOutput(TextReader reader)
|
||||
{
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
_logStreamWriter!.WriteLine(line);
|
||||
OnReadNewLine(line);
|
||||
|
||||
if (State == State.Starting)
|
||||
{
|
||||
if (StartedKeywords.Any(s => line.Contains(s)))
|
||||
State = State.Started;
|
||||
else if (FailedKeywords.Any(s => line.Contains(s)))
|
||||
{
|
||||
OnStartFailed();
|
||||
State = State.Stopped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
public virtual async Task StopAsync()
|
||||
{
|
||||
await StopGuardAsync();
|
||||
}
|
||||
|
||||
protected async Task StopGuardAsync()
|
||||
{
|
||||
_logStreamWriter?.Close();
|
||||
_logFileStream?.Close();
|
||||
|
||||
try
|
||||
{
|
||||
if (Instance == null || Instance.HasExited)
|
||||
return;
|
||||
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
if (Instance is { HasExited: false })
|
||||
{
|
||||
Instance.Kill();
|
||||
await Instance.WaitForExitAsync();
|
||||
}
|
||||
}
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Global.Logger.Error($"停止 {MainFile} 错误:\n" + e);
|
||||
Log.Error(e, "Stop {Name} failed", Instance.ProcessName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -92,184 +165,17 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅初始化 <see cref="Instance" />,不设定事件处理方法
|
||||
/// </summary>
|
||||
/// <param name="argument"></param>
|
||||
protected virtual void InitInstance(string argument)
|
||||
protected virtual void OnStarted()
|
||||
{
|
||||
Instance = new Process
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
FileName = Path.GetFullPath($"bin\\{MainFile}"),
|
||||
WorkingDirectory = $"{Global.NetchDir}\\bin",
|
||||
Arguments = argument,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = !RedirectStd,
|
||||
RedirectStandardOutput = RedirectStd,
|
||||
StandardOutputEncoding = RedirectStd ? InstanceOutputEncoding : null,
|
||||
RedirectStandardError = RedirectStd,
|
||||
StandardErrorEncoding = RedirectStd ? InstanceOutputEncoding : null,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
}
|
||||
};
|
||||
|
||||
if (!File.Exists(Instance.StartInfo.FileName))
|
||||
throw new MessageException(i18N.Translate($"bin\\{MainFile} file not found!"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认行为启动主程序
|
||||
/// </summary>
|
||||
/// <param name="argument">主程序启动参数</param>
|
||||
/// <param name="priority">进程优先级</param>
|
||||
/// <returns>是否成功启动</returns>
|
||||
protected void StartInstanceAuto(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
|
||||
{
|
||||
State = State.Starting;
|
||||
// 初始化程序
|
||||
InitInstance(argument);
|
||||
|
||||
if (RedirectToFile)
|
||||
OpenLogFile();
|
||||
|
||||
// 启动程序
|
||||
Instance!.Start();
|
||||
if (priority != ProcessPriorityClass.Normal)
|
||||
Instance.PriorityClass = priority;
|
||||
|
||||
if (RedirectStd)
|
||||
{
|
||||
Task.Run(() => ReadOutput(Instance.StandardOutput));
|
||||
Task.Run(() => ReadOutput(Instance.StandardError));
|
||||
|
||||
if (!StartedKeywords.Any())
|
||||
{
|
||||
State = State.Started;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 等待启动
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
switch (State)
|
||||
{
|
||||
case State.Started:
|
||||
Task.Run(OnKeywordStarted);
|
||||
return;
|
||||
case State.Stopped:
|
||||
Stop();
|
||||
CloseLogFile();
|
||||
OnKeywordStopped();
|
||||
throw new MessageException($"{Name} 控制器启动失败");
|
||||
}
|
||||
}
|
||||
|
||||
Stop();
|
||||
OnKeywordTimeout();
|
||||
throw new MessageException($"{Name} 控制器启动超时");
|
||||
}
|
||||
|
||||
#region FileStream
|
||||
|
||||
private void OpenLogFile()
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
_logStreamWriter = new StreamWriter(_logFileStream);
|
||||
|
||||
_flushFileStreamTimer.Elapsed += FlushFileStreamTimerEvent;
|
||||
_flushFileStreamTimer.Enabled = true;
|
||||
}
|
||||
|
||||
private void WriteLog(string line)
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_logStreamWriter!.WriteLine(line);
|
||||
}
|
||||
|
||||
private void CloseLogFile()
|
||||
{
|
||||
if (!RedirectToFile)
|
||||
return;
|
||||
|
||||
_flushFileStreamTimer.Enabled = false;
|
||||
_logStreamWriter?.Close();
|
||||
_logFileStream?.Close();
|
||||
_logStreamWriter = _logStreamWriter = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region virtual
|
||||
|
||||
protected virtual void OnReadNewLine(string line)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnKeywordStarted()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnKeywordStopped()
|
||||
protected virtual void OnStartFailed()
|
||||
{
|
||||
Utils.Utils.Open(LogPath);
|
||||
}
|
||||
|
||||
protected virtual void OnKeywordTimeout()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected void ReadOutput(TextReader reader)
|
||||
{
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
WriteLog(line);
|
||||
OnReadNewLine(line);
|
||||
|
||||
// State == State.Started if !StartedKeywords.Any()
|
||||
if (State == State.Starting)
|
||||
{
|
||||
if (StartedKeywords.Any(s => line.Contains(s)))
|
||||
State = State.Started;
|
||||
else if (StoppedKeywords.Any(s => line.Contains(s)))
|
||||
State = State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
CloseLogFile();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计时器存储日志
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void FlushFileStreamTimerEvent(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logStreamWriter!.Flush();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Global.Logger.Warning($"写入 {Name} 日志错误:\n" + exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public interface IController
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制器名
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public interface IModeController : IController
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public abstract void Start(in Mode mode);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,86 @@
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public static class MainController
|
||||
{
|
||||
public static Mode? Mode;
|
||||
public static Socks5Server? Socks5Server { get; private set; }
|
||||
|
||||
/// TCP or Both Server
|
||||
public static Server? Server;
|
||||
public static Server? Server { get; private set; }
|
||||
|
||||
private static Server? _udpServer;
|
||||
public static Mode? Mode { get; private set; }
|
||||
|
||||
public static readonly NTTController NTTController = new();
|
||||
private static IServerController? _serverController;
|
||||
private static IServerController? _udpServerController;
|
||||
|
||||
public static IServerController? ServerController
|
||||
{
|
||||
get => _serverController;
|
||||
private set => _serverController = value;
|
||||
}
|
||||
|
||||
public static IServerController? UdpServerController
|
||||
{
|
||||
get => _udpServerController ?? _serverController;
|
||||
set => _udpServerController = value;
|
||||
}
|
||||
|
||||
public static Server? UdpServer
|
||||
{
|
||||
get => _udpServer ?? Server;
|
||||
set => _udpServer = value;
|
||||
}
|
||||
public static IServerController? ServerController { get; private set; }
|
||||
|
||||
public static IModeController? ModeController { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
/// <exception cref="MessageException"></exception>
|
||||
public static ModeFeature ModeFeatures { get; private set; }
|
||||
|
||||
private static readonly AsyncSemaphore Lock = new(1);
|
||||
|
||||
public static async Task StartAsync(Server server, Mode mode)
|
||||
{
|
||||
await Task.Run(() => Start(server, mode));
|
||||
}
|
||||
using var releaser = await Lock.EnterAsync();
|
||||
|
||||
Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.Remark}");
|
||||
|
||||
if (await DnsUtils.LookupAsync(server.Hostname) == null)
|
||||
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
|
||||
|
||||
// TODO Disable NAT Type Test setting
|
||||
// cache STUN Server ip to prevent "Wrong STUN Server"
|
||||
DnsUtils.LookupAsync(Global.Settings.STUN_Server).Forget();
|
||||
|
||||
public static void Start(Server server, Mode mode)
|
||||
{
|
||||
Global.Logger.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
Server = server;
|
||||
Mode = mode;
|
||||
|
||||
// 刷新 DNS 缓存
|
||||
NativeMethods.RefreshDNSCache();
|
||||
|
||||
if (DnsUtils.Lookup(server.Hostname) == null)
|
||||
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
|
||||
|
||||
// 添加 Netch 到防火墙
|
||||
Firewall.AddNetchFwRules();
|
||||
await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules));
|
||||
|
||||
try
|
||||
{
|
||||
if (!ModeHelper.SkipServerController(server, mode))
|
||||
(ModeController, ModeFeatures) = ModeHelper.GetModeControllerByType(mode.Type, out var modePort, out var portName);
|
||||
|
||||
if (modePort != null)
|
||||
TryReleaseTcpPort((ushort)modePort, portName);
|
||||
|
||||
if (Server is Socks5Server socks5 && (!socks5.Auth() || ModeFeatures.HasFlag(ModeFeature.SupportSocks5Auth)))
|
||||
{
|
||||
StartServer(server, mode, out _serverController);
|
||||
Socks5Server = socks5;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start Server Controller to get a local socks5 server
|
||||
Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}");
|
||||
|
||||
ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
|
||||
|
||||
TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5");
|
||||
Socks5Server = await ServerController.StartAsync(server);
|
||||
|
||||
StatusPortInfoText.Socks5Port = Socks5Server.Port;
|
||||
StatusPortInfoText.UpdateShareLan();
|
||||
}
|
||||
|
||||
StartMode(mode);
|
||||
// Start Mode Controller
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
await ModeController.StartAsync(Socks5Server, mode);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stop();
|
||||
releaser.Dispose();
|
||||
await StopAsync();
|
||||
|
||||
switch (e)
|
||||
{
|
||||
@@ -89,81 +90,47 @@ namespace Netch.Controllers
|
||||
case MessageException:
|
||||
throw;
|
||||
default:
|
||||
Global.Logger.Error(e.ToString());
|
||||
Global.Logger.ShowLog();
|
||||
throw new MessageException($"未处理异常\n{e.Message}");
|
||||
Log.Error(e, "Unhandled Exception When Start MainController");
|
||||
Utils.Utils.Open(Constants.LogFile);
|
||||
throw new MessageException($"{i18N.Translate("Unhandled Exception")}\n{e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void StartServer(Server server, Mode mode, out IServerController controller)
|
||||
{
|
||||
controller = ServerHelper.GetUtilByTypeName(server.Type).GetController();
|
||||
|
||||
TryReleaseTcpPort(controller.Socks5LocalPort(), "Socks5");
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
|
||||
|
||||
controller.Start(in server, mode);
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
if (socks5.Auth())
|
||||
StatusPortInfoText.Socks5Port = controller.Socks5LocalPort();
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusPortInfoText.Socks5Port = controller.Socks5LocalPort();
|
||||
}
|
||||
}
|
||||
|
||||
private static void StartMode(Mode mode)
|
||||
{
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName);
|
||||
|
||||
if (port != null)
|
||||
TryReleaseTcpPort((ushort)port, portName);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
|
||||
ModeController.Start(mode);
|
||||
}
|
||||
|
||||
public static async Task StopAsync()
|
||||
{
|
||||
await Task.Run(Stop);
|
||||
}
|
||||
if (Lock.CurrentCount == 0)
|
||||
{
|
||||
(await Lock.EnterAsync()).Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public static void Stop()
|
||||
{
|
||||
if (_serverController == null && ModeController == null)
|
||||
using var _ = await Lock.EnterAsync();
|
||||
|
||||
if (ServerController == null && ModeController == null)
|
||||
return;
|
||||
|
||||
Log.Information("Stop Main Controller");
|
||||
StatusPortInfoText.Reset();
|
||||
|
||||
_ = Task.Run(() => NTTController.Stop());
|
||||
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(() => ServerController?.Stop()),
|
||||
Task.Run(() => ModeController?.Stop())
|
||||
Task.Run(() => ServerController?.StopAsync()),
|
||||
Task.Run(() => ModeController?.StopAsync())
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error(e.ToString());
|
||||
Global.Logger.ShowLog();
|
||||
Log.Error(e, "MainController Stop Error");
|
||||
}
|
||||
|
||||
ModeController = null;
|
||||
ServerController = null;
|
||||
ModeController = null;
|
||||
ModeFeatures = 0;
|
||||
}
|
||||
|
||||
public static void PortCheck(ushort port, string portName, PortType portType = PortType.Both)
|
||||
@@ -186,16 +153,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
|
||||
{
|
||||
string fileName;
|
||||
try
|
||||
{
|
||||
fileName = p.MainModule?.FileName ?? throw new Exception(); // TODO what's this exception?
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Warning(e.ToString());
|
||||
var fileName = p.MainModule?.FileName;
|
||||
if (fileName == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileName.StartsWith(Global.NetchDir))
|
||||
{
|
||||
@@ -210,5 +170,30 @@ namespace Netch.Controllers
|
||||
|
||||
PortCheck(port, portName, PortType.TCP);
|
||||
}
|
||||
|
||||
public static async Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
|
||||
}
|
||||
|
||||
public static async Task<int?> HttpConnectAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
try
|
||||
{
|
||||
return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +1,72 @@
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using static Netch.Interops.RedirectorInterop;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
using static Netch.Interops.Redirector;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class NFController : IModeController
|
||||
{
|
||||
private Server? _server;
|
||||
private Mode? _mode;
|
||||
private RedirectorConfig _rdrConfig = null!;
|
||||
|
||||
private static readonly ServiceController NFService = new("netfilter2");
|
||||
|
||||
private const string BinDriver = "bin\\nfdriver.sys";
|
||||
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
|
||||
|
||||
public string Name { get; } = "Redirector";
|
||||
public string Name => "Redirector";
|
||||
|
||||
public void Start(in Mode mode)
|
||||
public async Task StartAsync(Socks5Server server, Mode mode)
|
||||
{
|
||||
_server = server;
|
||||
_mode = mode;
|
||||
_rdrConfig = Global.Settings.Redirector;
|
||||
CheckDriver();
|
||||
|
||||
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());
|
||||
Dial(NameList.AIO_FILTERLOOPBACK, "false");
|
||||
Dial(NameList.AIO_FILTERINTRANET, "true");
|
||||
Dial(NameList.AIO_FILTERPARENT, _rdrConfig.ChildProcessHandle.ToString().ToLower());
|
||||
Dial(NameList.AIO_FILTERICMP, _rdrConfig.FilterICMP.ToString().ToLower());
|
||||
Dial(NameList.AIO_ICMPING, _rdrConfig.ICMPDelay.ToString());
|
||||
|
||||
// Server
|
||||
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);
|
||||
Dial(NameList.AIO_FILTERUDP, _rdrConfig.FilterProtocol.HasFlag(PortType.UDP).ToString().ToLower());
|
||||
Dial(NameList.AIO_FILTERTCP, _rdrConfig.FilterProtocol.HasFlag(PortType.TCP).ToString().ToLower());
|
||||
|
||||
Dial(NameList.AIO_TGTHOST, await server.AutoResolveHostnameAsync());
|
||||
Dial(NameList.AIO_TGTPORT, server.Port.ToString());
|
||||
Dial(NameList.AIO_TGTUSER, server.Username ?? string.Empty);
|
||||
Dial(NameList.AIO_TGTPASS, server.Password ?? string.Empty);
|
||||
|
||||
// Mode Rule
|
||||
dial_Name(mode);
|
||||
DialRule(_mode);
|
||||
|
||||
// Features
|
||||
Dial(NameList.TYPE_DNSHOST, Global.Settings.Redirector.DNSHijack ? Global.Settings.Redirector.DNSHijackHost : "");
|
||||
// DNS
|
||||
Dial(NameList.AIO_FILTERDNS, _rdrConfig.DNSHijack.ToString().ToLower());
|
||||
if (_rdrConfig.DNSHijack)
|
||||
{
|
||||
var dns = new Uri(DnsUtils.AppendScheme(DnsUtils.AppendPort(_rdrConfig.DNSHijackHost), "udp"));
|
||||
Dial(NameList.AIO_DNSHOST, dns.Host);
|
||||
Dial(NameList.AIO_DNSPORT, dns.Port.ToString());
|
||||
}
|
||||
|
||||
if (!Init())
|
||||
throw new MessageException("Redirector Start failed, run Netch with \"-console\" argument");
|
||||
if (!await InitAsync())
|
||||
throw new MessageException("Redirector start failed.");
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
public async Task StopAsync()
|
||||
{
|
||||
Free();
|
||||
await FreeAsync();
|
||||
}
|
||||
|
||||
#region CheckRule
|
||||
@@ -63,14 +81,14 @@ namespace Netch.Controllers
|
||||
try
|
||||
{
|
||||
if (r.StartsWith("!"))
|
||||
return Dial(NameList.TYPE_ADDNAME, r.Substring(1));
|
||||
return Dial(NameList.AIO_ADDNAME, r.Substring(1));
|
||||
|
||||
return Dial(NameList.TYPE_ADDNAME, r);
|
||||
return Dial(NameList.AIO_ADDNAME, r);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (clear)
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
Dial(NameList.AIO_CLRNAME, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,102 +100,51 @@ namespace Netch.Controllers
|
||||
public static bool CheckRules(IEnumerable<string> rules, out IEnumerable<string> results)
|
||||
{
|
||||
results = rules.Where(r => !CheckCppRegex(r, false));
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
Dial(NameList.AIO_CLRNAME, "");
|
||||
return !results.Any();
|
||||
}
|
||||
|
||||
public static string GenerateInvalidRulesMessage(IEnumerable<string> rules)
|
||||
{
|
||||
return $"{string.Join("\n", rules)}\nAbove rules does not conform to C++ regular expression syntax";
|
||||
return $"{string.Join("\n", rules)}\n" + i18N.Translate("Above rules does not conform to C++ regular expression syntax");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void dial_Server(in PortType portType)
|
||||
private void DialRule(Mode mode)
|
||||
{
|
||||
if (portType == PortType.Both)
|
||||
{
|
||||
dial_Server(PortType.TCP);
|
||||
dial_Server(PortType.UDP);
|
||||
return;
|
||||
}
|
||||
|
||||
int offset;
|
||||
Server server;
|
||||
IServerController controller;
|
||||
|
||||
if (portType == PortType.UDP)
|
||||
{
|
||||
offset = UdpNameListOffset;
|
||||
server = MainController.UdpServer!;
|
||||
controller = MainController.UdpServerController!;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
server = MainController.Server!;
|
||||
controller = MainController.ServerController!;
|
||||
}
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
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.Redirector.RedirectorSS)
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
Dial(NameList.TYPE_CLRNAME, "");
|
||||
Dial(NameList.AIO_CLRNAME, "");
|
||||
var invalidList = new List<string>();
|
||||
foreach (var s in mode.FullRule)
|
||||
foreach (var s in mode.GetRules())
|
||||
{
|
||||
if (s.StartsWith("!"))
|
||||
{
|
||||
if (!Dial(NameList.TYPE_BYPNAME, s.Substring(1)))
|
||||
if (!Dial(NameList.AIO_BYPNAME, s.Substring(1)))
|
||||
invalidList.Add(s);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Dial(NameList.TYPE_ADDNAME, s))
|
||||
if (!Dial(NameList.AIO_ADDNAME, s))
|
||||
invalidList.Add(s);
|
||||
}
|
||||
|
||||
if (invalidList.Any())
|
||||
throw new MessageException(GenerateInvalidRulesMessage(invalidList));
|
||||
|
||||
Dial(NameList.TYPE_ADDNAME, @"NTT\.exe");
|
||||
Dial(NameList.TYPE_BYPNAME, "^" + Global.NetchDir.ToRegexString() + @"((?!NTT\.exe).)*$");
|
||||
// Bypass Self
|
||||
Dial(NameList.AIO_BYPNAME, "^" + Global.NetchDir.ToRegexString());
|
||||
}
|
||||
|
||||
#region DriverUtil
|
||||
|
||||
private static void CheckDriver()
|
||||
{
|
||||
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
|
||||
var binFileVersion = Utils.Utils.GetFileVersion(Constants.NFDriver);
|
||||
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
|
||||
|
||||
Global.Logger.Info("内置驱动版本: " + binFileVersion);
|
||||
Global.Logger.Info("系统驱动版本: " + systemFileVersion);
|
||||
Log.Information("Built-in netfilter2 driver version: {Name}", binFileVersion);
|
||||
Log.Information("Installed netfilter2 driver version: {Name}", systemFileVersion);
|
||||
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
@@ -207,7 +174,7 @@ namespace Netch.Controllers
|
||||
if (!reinstall)
|
||||
return;
|
||||
|
||||
Global.Logger.Info("更新驱动");
|
||||
Log.Information("Update netfilter2 driver");
|
||||
UninstallDriver();
|
||||
InstallDriver();
|
||||
}
|
||||
@@ -218,32 +185,32 @@ namespace Netch.Controllers
|
||||
/// <returns>驱动是否安装成功</returns>
|
||||
private static void InstallDriver()
|
||||
{
|
||||
Global.Logger.Info("安装 NF 驱动");
|
||||
Log.Information("Install netfilter2 driver");
|
||||
Global.MainForm.StatusText(i18N.Translate("Installing netfilter2 driver"));
|
||||
|
||||
if (!File.Exists(BinDriver))
|
||||
if (!File.Exists(Constants.NFDriver))
|
||||
throw new MessageException(i18N.Translate("builtin driver files missing, can't install NF driver"));
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(BinDriver, SystemDriver);
|
||||
File.Copy(Constants.NFDriver, SystemDriver);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error("驱动复制失败\n" + e);
|
||||
throw new MessageException($"Copy NF driver file failed\n{e.Message}");
|
||||
Log.Error(e, "Copy netfilter2.sys failed\n");
|
||||
throw new MessageException($"Copy netfilter2.sys failed\n{e.Message}");
|
||||
}
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Register driver"));
|
||||
// 注册驱动文件
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result == NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Global.Logger.Info("驱动安装成功");
|
||||
Log.Information("Install netfilter2 driver finished");
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.Logger.Error($"注册驱动失败,返回值:{result}");
|
||||
throw new MessageException($"Register NF driver failed\n{result}");
|
||||
Log.Error("Register netfilter2 failed: {Result}", result);
|
||||
throw new MessageException($"Register netfilter2 failed\n{result}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +220,7 @@ namespace Netch.Controllers
|
||||
/// <returns>是否成功卸载</returns>
|
||||
public static bool UninstallDriver()
|
||||
{
|
||||
Global.Logger.Info("卸载 NF 驱动");
|
||||
Log.Information("Uninstall netfilter2");
|
||||
try
|
||||
{
|
||||
if (NFService.Status == ServiceControllerStatus.Running)
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class NTTController : Guard, IController
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "NTT.exe";
|
||||
|
||||
public override string Name { get; } = "NTT";
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动 NatTypeTester
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<(string?, string?, string?)> Start()
|
||||
{
|
||||
string? localEnd = null, publicEnd = null, result = null, bindingTest = null;
|
||||
|
||||
try
|
||||
{
|
||||
InitInstance($" {Global.Settings.STUN_Server} {Global.Settings.STUN_Server_Port}");
|
||||
Instance!.Start();
|
||||
|
||||
var output = await Instance.StandardOutput.ReadToEndAsync();
|
||||
var error = await Instance.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), $"{output}\r\n{error}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Warning($"写入 {Name} 日志错误:\n" + e.Message);
|
||||
}
|
||||
|
||||
if (output.IsNullOrWhiteSpace())
|
||||
if (!error.IsNullOrWhiteSpace())
|
||||
{
|
||||
error = error.Trim();
|
||||
var errorFirst = error.Substring(0, error.IndexOf('\n')).Trim();
|
||||
return (errorFirst.SplitTrimEntries(':').Last(), null, null);
|
||||
}
|
||||
|
||||
foreach (var line in output.Split('\n'))
|
||||
{
|
||||
var str = line.SplitTrimEntries(':');
|
||||
if (str.Length < 2)
|
||||
continue;
|
||||
|
||||
var key = str[0];
|
||||
var value = str[1];
|
||||
switch (key)
|
||||
{
|
||||
case "Other address is":
|
||||
case "Nat mapping behavior":
|
||||
case "Nat filtering behavior":
|
||||
break;
|
||||
case "Binding test":
|
||||
bindingTest = value;
|
||||
break;
|
||||
case "Local address":
|
||||
localEnd = value;
|
||||
break;
|
||||
case "Mapped address":
|
||||
publicEnd = value;
|
||||
break;
|
||||
case "result":
|
||||
result = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bindingTest == "Fail")
|
||||
result = "Fail";
|
||||
|
||||
return (result, localEnd, publicEnd);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error($"{Name} 控制器出错:\n" + e);
|
||||
try
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return (null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +1,93 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Netch.Forms;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Servers;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class PcapController : Guard, IModeController
|
||||
{
|
||||
public override string Name { get; } = "pcap2socks";
|
||||
private readonly LogForm _form;
|
||||
private Mode? _mode;
|
||||
private Server? _server;
|
||||
|
||||
public override string MainFile { get; protected set; } = "pcap2socks.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "└" };
|
||||
|
||||
private readonly OutboundAdapter _outbound = new();
|
||||
|
||||
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
|
||||
|
||||
private LogForm? _form;
|
||||
|
||||
public void Start(in Mode mode)
|
||||
public PcapController() : base("pcap2socks.exe", encoding: Encoding.UTF8)
|
||||
{
|
||||
var server = MainController.Server!;
|
||||
|
||||
_form = new LogForm(Global.MainForm);
|
||||
_form.CreateControl();
|
||||
}
|
||||
|
||||
var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}");
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
argument.Append($" --destination {server.AutoResolveHostname()}:{server.Port}");
|
||||
protected override IEnumerable<string> StartedKeywords { get; } = new[] { "└" };
|
||||
|
||||
public override string Name => "pcap2socks";
|
||||
|
||||
public async Task StartAsync(Socks5Server server, Mode mode)
|
||||
{
|
||||
_server = server;
|
||||
_mode = mode;
|
||||
|
||||
var outboundNetworkInterface = NetworkInterfaceUtils.GetBest();
|
||||
|
||||
var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.Id}");
|
||||
if (_server is Socks5Server socks5 && !socks5.Auth())
|
||||
argument.Append($" --destination {await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
|
||||
else
|
||||
argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
Trace.Assert(false);
|
||||
|
||||
argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}");
|
||||
StartInstanceAuto(argument.ToString());
|
||||
argument.Append($" {_mode.GetRules().FirstOrDefault() ?? "-P n"}");
|
||||
await StartGuardAsync(argument.ToString());
|
||||
}
|
||||
|
||||
public override async Task StopAsync()
|
||||
{
|
||||
Global.MainForm.Invoke(new Action(() => { _form.Close(); }));
|
||||
await StopGuardAsync();
|
||||
}
|
||||
|
||||
~PcapController()
|
||||
{
|
||||
_form.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnReadNewLine(string line)
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (!_form!.IsDisposed)
|
||||
if (!_form.IsDisposed)
|
||||
_form.richTextBox1.AppendText(line + "\n");
|
||||
}));
|
||||
}
|
||||
|
||||
protected override void OnKeywordStarted()
|
||||
protected override void OnStarted()
|
||||
{
|
||||
Global.MainForm.BeginInvoke(new Action(() => { _form!.Show(); }));
|
||||
Global.MainForm.BeginInvoke(new Action(() => _form.Show()));
|
||||
}
|
||||
|
||||
protected override void OnKeywordStopped()
|
||||
protected override void OnStartFailed()
|
||||
{
|
||||
if (File.ReadAllText(LogPath).Length == 0)
|
||||
if (new FileInfo(LogPath).Length == 0)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies");
|
||||
});
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies");
|
||||
})
|
||||
.Forget();
|
||||
|
||||
throw new MessageException("Pleases install pcap2socks's dependency");
|
||||
}
|
||||
|
||||
Utils.Utils.Open(LogPath);
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
_form!.Close();
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,51 @@
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using static Netch.Interops.TUNInterop;
|
||||
using Netch.Enums;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Interops;
|
||||
using Netch.Models;
|
||||
using Netch.Servers;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
using static Netch.Interops.tun2socks;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNController : IModeController
|
||||
{
|
||||
private readonly List<string> _directIPs = new();
|
||||
private const string DummyDns = "6.6.6.6";
|
||||
|
||||
private readonly List<string> _proxyIPs = new();
|
||||
private readonly DNSController _aioDnsController = new();
|
||||
|
||||
public readonly DNSController DNSController = new();
|
||||
private Mode _mode = null!;
|
||||
private IPAddress? _serverRemoteAddress;
|
||||
private TUNConfig _tunConfig = null!;
|
||||
|
||||
public string Name { get; } = "tun2socks";
|
||||
private NetRoute _tun;
|
||||
private NetRoute _outbound;
|
||||
|
||||
private readonly OutboundAdapter _outboundAdapter = new();
|
||||
private IAdapter _tunAdapter = null!;
|
||||
private IPAddress _serverAddresses = null!;
|
||||
public string Name => "tun2socks";
|
||||
|
||||
public void Start(in Mode mode)
|
||||
public async Task StartAsync(Socks5Server server, Mode mode)
|
||||
{
|
||||
var server = MainController.Server!;
|
||||
_serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start
|
||||
_mode = mode;
|
||||
_tunConfig = Global.Settings.TUNTAP;
|
||||
|
||||
if (server is Socks5LocalServer socks5Bridge)
|
||||
_serverRemoteAddress = await DnsUtils.LookupAsync(socks5Bridge.RemoteHostname);
|
||||
|
||||
if (_serverRemoteAddress != null && IPAddress.IsLoopback(_serverRemoteAddress))
|
||||
_serverRemoteAddress = null;
|
||||
|
||||
_outbound = NetRoute.GetBestRouteTemplate();
|
||||
CheckDriver();
|
||||
|
||||
Dial(NameList.TYPE_ADAPMTU, "1500");
|
||||
Dial(NameList.TYPE_BYPBIND, _outboundAdapter.Address.ToString());
|
||||
Dial(NameList.TYPE_BYPBIND, _outbound.Gateway);
|
||||
Dial(NameList.TYPE_BYPLIST, "disabled");
|
||||
|
||||
#region Server
|
||||
@@ -45,11 +56,11 @@ namespace Netch.Controllers
|
||||
Dial(NameList.TYPE_UDPREST, "");
|
||||
Dial(NameList.TYPE_UDPTYPE, "Socks5");
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
if (server is Socks5Server socks5)
|
||||
{
|
||||
Dial(NameList.TYPE_TCPHOST, $"{server.AutoResolveHostname()}:{server.Port}");
|
||||
Dial(NameList.TYPE_TCPHOST, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
|
||||
|
||||
Dial(NameList.TYPE_UDPHOST, $"{server.AutoResolveHostname()}:{server.Port}");
|
||||
Dial(NameList.TYPE_UDPHOST, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
|
||||
|
||||
if (socks5.Auth())
|
||||
{
|
||||
@@ -62,245 +73,136 @@ namespace Netch.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
Dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
|
||||
Dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
Trace.Assert(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DNS
|
||||
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
if (_tunConfig.UseCustomDNS)
|
||||
{
|
||||
Dial(NameList.TYPE_DNSADDR, Global.Settings.TUNTAP.HijackDNS);
|
||||
Dial(NameList.TYPE_DNSADDR, _tunConfig.HijackDNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
|
||||
DNSController.Start();
|
||||
await _aioDnsController.StartAsync();
|
||||
Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Global.Logger.Debug("tun2socks init");
|
||||
Init();
|
||||
if (!Init())
|
||||
throw new MessageException("tun2socks start failed.");
|
||||
|
||||
_tunAdapter = new TunAdapter();
|
||||
var tunIndex = (int)RouteHelper.ConvertLuidToIndex(tun_luid());
|
||||
_tun = NetRoute.TemplateBuilder(_tunConfig.Gateway, tunIndex);
|
||||
|
||||
NativeMethods.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
Global.Settings.TUNTAP.Address,
|
||||
(byte)Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
|
||||
_tunAdapter.InterfaceIndex);
|
||||
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
|
||||
_tunConfig.Address,
|
||||
(byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask),
|
||||
(ulong)tunIndex);
|
||||
|
||||
SetupRouteTable(mode);
|
||||
SetupRouteTable();
|
||||
}
|
||||
|
||||
private readonly string BinDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll");
|
||||
private readonly string SysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
|
||||
public async Task StopAsync()
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
FreeAsync(),
|
||||
Task.Run(ClearRouteTable),
|
||||
_aioDnsController.StopAsync()
|
||||
};
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
private void CheckDriver()
|
||||
{
|
||||
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);
|
||||
string binDriver = Path.Combine(Global.NetchDir, Constants.WintunDllFile);
|
||||
string sysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
|
||||
|
||||
var binHash = Utils.Utils.SHA256CheckSum(binDriver);
|
||||
var sysHash = Utils.Utils.SHA256CheckSum(sysDriver);
|
||||
Log.Information("Built-in wintun.dll Hash: {Hash}", binHash);
|
||||
Log.Information("Installed wintun.dll Hash: {Hash}", sysHash);
|
||||
if (binHash == sysHash)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(BinDriver, SysDriver, true);
|
||||
Log.Information("Copy wintun.dll to System Directory");
|
||||
File.Copy(binDriver, sysDriver, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error(e.ToString());
|
||||
Log.Error(e, "Copy wintun.dll failed");
|
||||
throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
#region Route
|
||||
|
||||
private void SetupRouteTable()
|
||||
{
|
||||
var tasks = new[]
|
||||
Global.MainForm.StatusText(i18N.Translate("Setup Route Table Rule"));
|
||||
|
||||
// Server Address
|
||||
if (_serverRemoteAddress != null)
|
||||
RouteUtils.CreateRoute(_outbound.FillTemplate(_serverRemoteAddress.ToString(), 32));
|
||||
|
||||
// Global Bypass IPs
|
||||
RouteUtils.CreateRouteFill(_outbound, _tunConfig.BypassIPs);
|
||||
|
||||
var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex);
|
||||
switch (_mode.Type)
|
||||
{
|
||||
Task.Run(Free),
|
||||
Task.Run(ClearRouteTable),
|
||||
Task.Run(DNSController.Stop)
|
||||
};
|
||||
case ModeType.ProxyRuleIPs:
|
||||
// rules
|
||||
RouteUtils.CreateRouteFill(_tun, _mode.GetRules());
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置绕行规则
|
||||
/// </summary>
|
||||
/// <returns>是否设置成功</returns>
|
||||
private void SetupRouteTable(Mode mode)
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
|
||||
Global.Logger.Info("设置路由规则");
|
||||
|
||||
Global.Logger.Info("绕行 → 服务器 IP");
|
||||
if (!IPAddress.IsLoopback(_serverAddresses))
|
||||
RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound);
|
||||
|
||||
Global.Logger.Info("绕行 → 全局绕过 IP");
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.BypassIPs, RouteType.Outbound);
|
||||
|
||||
#region Rule IPs
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 1:
|
||||
// 代理规则 IP
|
||||
Global.Logger.Info("代理 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
if (_tunConfig.ProxyDNS)
|
||||
{
|
||||
Global.Logger.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.HijackDNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
|
||||
else
|
||||
RouteAction(Action.Create, $"{Global.Settings.AioDNS.OtherDNS}/32", RouteType.TUNTAP);
|
||||
tunNetworkInterface.SetDns(DummyDns);
|
||||
// proxy dummy dns
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32));
|
||||
|
||||
if (!_tunConfig.UseCustomDNS)
|
||||
// proxy AioDNS other dns
|
||||
RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32));
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
// 绕过规则 IP
|
||||
case ModeType.BypassRuleIPs:
|
||||
RouteUtils.CreateRouteFill(_outbound, _mode.GetRules());
|
||||
|
||||
Global.Logger.Info("绕行 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
|
||||
tunNetworkInterface.SetDns(DummyDns);
|
||||
|
||||
if (!_tunConfig.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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (mode.Type == 2)
|
||||
{
|
||||
Global.Logger.Info("代理 → 全局");
|
||||
SetInterface(RouteType.TUNTAP, 0);
|
||||
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP, record: false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetInterface(RouteType routeType, int? metric = null)
|
||||
private void ClearRouteTable()
|
||||
{
|
||||
var adapter = routeType == RouteType.Outbound ? _outboundAdapter : _tunAdapter;
|
||||
if (_serverRemoteAddress != null)
|
||||
RouteUtils.DeleteRoute(_outbound.FillTemplate(_serverRemoteAddress.ToString(), 32));
|
||||
|
||||
var arguments = $"interface ip set interface {adapter.InterfaceIndex} ";
|
||||
if (metric != null)
|
||||
arguments += $"metric={metric} ";
|
||||
RouteUtils.DeleteRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs);
|
||||
|
||||
Utils.Utils.ProcessRunHiddenAsync("netsh", arguments).Wait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除绕行规则
|
||||
/// </summary>
|
||||
private bool ClearRouteTable()
|
||||
{
|
||||
var mode = MainController.Mode!;
|
||||
RouteAction(Action.Delete, _directIPs, RouteType.Outbound);
|
||||
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
|
||||
_directIPs.Clear();
|
||||
_proxyIPs.Clear();
|
||||
if (mode.Type == 2)
|
||||
switch (_mode.Type)
|
||||
{
|
||||
SetInterface(RouteType.Outbound);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Package
|
||||
|
||||
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0, bool record = true)
|
||||
{
|
||||
foreach (var address in ipNetworks)
|
||||
RouteAction(action, address, routeType, metric);
|
||||
}
|
||||
|
||||
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0, bool record = true)
|
||||
{
|
||||
#region
|
||||
|
||||
if (!TryParseIPNetwork(ipNetwork, out var ip, out var cidr))
|
||||
return false;
|
||||
|
||||
IAdapter adapter = routeType switch
|
||||
{
|
||||
RouteType.Outbound => _outboundAdapter,
|
||||
RouteType.TUNTAP => _tunAdapter,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
|
||||
};
|
||||
|
||||
List<string> ipList = routeType switch
|
||||
{
|
||||
RouteType.Outbound => _directIPs,
|
||||
RouteType.TUNTAP => _proxyIPs,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
|
||||
};
|
||||
|
||||
string gateway = adapter.Gateway.ToString();
|
||||
var index = adapter.InterfaceIndex;
|
||||
|
||||
#endregion
|
||||
|
||||
bool result;
|
||||
switch (action)
|
||||
{
|
||||
case Action.Create:
|
||||
result = NativeMethods.CreateRoute(AddressFamily.InterNetwork, ip, (byte)cidr, gateway, index, metric);
|
||||
if (result && record)
|
||||
ipList.Add(ipNetwork);
|
||||
|
||||
case ModeType.BypassRuleIPs:
|
||||
RouteUtils.DeleteRouteFill(_outbound, _mode.GetRules());
|
||||
NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex);
|
||||
break;
|
||||
case Action.Delete:
|
||||
result = NativeMethods.DeleteRoute(AddressFamily.InterNetwork, ip, (byte)cidr, gateway, index, metric);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(action), action, null);
|
||||
}
|
||||
|
||||
Global.Logger.Debug($"{action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})");
|
||||
if (!result)
|
||||
Global.Logger.Warning($"Failed to invoke {action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TryParseIPNetwork(string ipNetwork, out string ip, out int cidr)
|
||||
{
|
||||
ip = null!;
|
||||
cidr = 0;
|
||||
|
||||
var s = ipNetwork.Split('/');
|
||||
if (s.Length != 2)
|
||||
{
|
||||
Global.Logger.Warning($"Failed to parse rule {ipNetwork}");
|
||||
return false;
|
||||
}
|
||||
|
||||
ip = s[0];
|
||||
cidr = int.Parse(s[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum RouteType
|
||||
{
|
||||
Outbound,
|
||||
TUNTAP
|
||||
}
|
||||
|
||||
private enum Action
|
||||
{
|
||||
Create,
|
||||
Delete
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@@ -8,6 +6,9 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -19,7 +20,7 @@ namespace Netch.Controllers
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2021";
|
||||
|
||||
public const string AssemblyVersion = @"1.8.3";
|
||||
public const string AssemblyVersion = @"1.9.2";
|
||||
private const string Suffix = @"";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
@@ -36,48 +37,43 @@ namespace Netch.Controllers
|
||||
|
||||
public static event EventHandler? NewVersionNotFound;
|
||||
|
||||
public static async Task Check(bool isPreRelease)
|
||||
public static async Task CheckAsync(bool isPreRelease)
|
||||
{
|
||||
try
|
||||
{
|
||||
var updater = new GitHubRelease(Owner, Repo);
|
||||
var url = updater.AllReleaseUrl;
|
||||
|
||||
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
|
||||
var (_, json) = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
|
||||
|
||||
var releases = JsonSerializer.Deserialize<List<Release>>(json)!;
|
||||
LatestRelease = GetLatestRelease(releases, isPreRelease);
|
||||
Global.Logger.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
|
||||
Log.Information("Github latest release: {Version}", LatestRelease.tag_name);
|
||||
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
|
||||
{
|
||||
Global.Logger.Info("发现新版本");
|
||||
NewVersionFound?.Invoke(null, new EventArgs());
|
||||
Log.Information("Found newer version");
|
||||
NewVersionFound?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.Logger.Info("目前是最新版本");
|
||||
NewVersionNotFound?.Invoke(null, new EventArgs());
|
||||
Log.Information("Already the latest version");
|
||||
NewVersionNotFound?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is WebException)
|
||||
Global.Logger.Warning($"获取新版本失败: {e.Message}");
|
||||
Log.Warning(e, "Get releases failed");
|
||||
else
|
||||
Global.Logger.Warning(e.ToString());
|
||||
Log.Error(e, "Get releases error");
|
||||
|
||||
NewVersionFoundFailed?.Invoke(null, new EventArgs());
|
||||
NewVersionFoundFailed?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetLatestUpdateFileNameAndHash(out string fileName, out string sha256, string? keyword = null)
|
||||
public static (string fileName, string sha256) GetLatestUpdateFileNameAndHash(string? keyword = null)
|
||||
{
|
||||
fileName = string.Empty;
|
||||
sha256 = string.Empty;
|
||||
|
||||
var matches = Regex.Matches(LatestRelease.body, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline)
|
||||
.Cast<Match>()
|
||||
.Skip(2);
|
||||
var matches = Regex.Matches(LatestRelease.body, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline).Skip(2);
|
||||
/*
|
||||
Skip(2)
|
||||
|
||||
@@ -87,8 +83,7 @@ namespace Netch.Controllers
|
||||
|
||||
Match match = keyword == null ? matches.First() : matches.First(m => m.Groups["filename"].Value.Contains(keyword));
|
||||
|
||||
fileName = match.Groups["filename"].Value;
|
||||
sha256 = match.Groups["sha256"].Value;
|
||||
return (match.Groups["filename"].Value, match.Groups["sha256"].Value);
|
||||
}
|
||||
|
||||
public static string GetLatestReleaseContent()
|
||||
@@ -105,7 +100,7 @@ namespace Netch.Controllers
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
|
||||
private static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
|
||||
{
|
||||
if (!isPreRelease)
|
||||
releases = releases.Where(release => !release.prerelease);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
namespace Netch.Models
|
||||
namespace Netch.Enums
|
||||
{
|
||||
public enum LogLevel
|
||||
{
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
DEBUG
|
||||
ERROR
|
||||
}
|
||||
}
|
||||
13
Netch/Enums/ModeFeature.cs
Normal file
13
Netch/Enums/ModeFeature.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Netch.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum ModeFeature
|
||||
{
|
||||
SupportSocks5 = 0,
|
||||
SupportIPv4 = 0,
|
||||
SupportSocks5Auth = 0b_0001,
|
||||
SupportIPv6 = 0b_0100
|
||||
}
|
||||
}
|
||||
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,4 +1,4 @@
|
||||
namespace Netch.Models
|
||||
namespace Netch.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态
|
||||
@@ -7,5 +7,7 @@ namespace Netch
|
||||
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
public static bool AlwaysShowNewVersionFound { get; set; }
|
||||
|
||||
public static bool NoSupport { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Netch.Forms
|
||||
|
||||
@@ -50,13 +50,13 @@ namespace Netch.Forms
|
||||
MessageBoxX.Show(i18N.Translate("Please select an IP"));
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
private async void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Settings.TUNTAP.BypassIPs.Clear();
|
||||
foreach (var ip in IPListBox.Items)
|
||||
Global.Settings.TUNTAP.BypassIPs.Add((string)ip);
|
||||
|
||||
Configuration.Save();
|
||||
await Configuration.SaveAsync();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
|
||||
2
Netch/Forms/LogForm.Designer.cs
generated
2
Netch/Forms/LogForm.Designer.cs
generated
@@ -74,7 +74,7 @@ namespace Netch.Forms
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.Text = "LogForm";
|
||||
this.Load += new System.EventHandler(this.Notifycation_Load);
|
||||
this.Load += new System.EventHandler(this.LogForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using Vanara.PInvoke;
|
||||
using static Vanara.PInvoke.User32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using static Windows.Win32.PInvoke;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -34,21 +35,21 @@ namespace Netch.Forms
|
||||
|
||||
private void Parent_Activated(object? sender, EventArgs? e)
|
||||
{
|
||||
SetWindowPos(Handle,
|
||||
HWND.HWND_TOPMOST,
|
||||
SetWindowPos(new HWND(Handle),
|
||||
new HWND(-1),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
|
||||
SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW);
|
||||
|
||||
SetWindowPos(Handle,
|
||||
HWND.HWND_NOTOPMOST,
|
||||
SetWindowPos(new HWND(Handle),
|
||||
new HWND(-2),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
|
||||
SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
private void richTextBox1_TextChanged(object? sender, EventArgs? e)
|
||||
@@ -60,7 +61,7 @@ namespace Netch.Forms
|
||||
richTextBox1.ScrollToCaret();
|
||||
}
|
||||
|
||||
private void Notifycation_Load(object? sender, EventArgs? e)
|
||||
private void LogForm_Load(object? sender, EventArgs? e)
|
||||
{
|
||||
_parent.LocationChanged += Parent_Move;
|
||||
_parent.SizeChanged += Parent_Move;
|
||||
|
||||
144
Netch/Forms/MainForm.Designer.cs
generated
144
Netch/Forms/MainForm.Designer.cs
generated
@@ -35,18 +35,19 @@
|
||||
this.ModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CreateProcessModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CreateRouteTableRuleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ManageSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SubscriptionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ManageSubscriptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UpdateServersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OpenDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ShowHideConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CleanDNSCacheToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.RemoveNetchFirewallRulesToolStripMenuItem = 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();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CheckForUpdateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.FAQToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ForceExitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AboutToolStripButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.NewVersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
this.VersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
@@ -72,6 +73,7 @@
|
||||
this.DownloadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.UploadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.blankToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.HttpStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.NatTypeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.NatTypeStatusLightLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
@@ -109,10 +111,10 @@
|
||||
this.MenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ServerToolStripMenuItem,
|
||||
this.ModeToolStripMenuItem,
|
||||
this.SubscribeToolStripMenuItem,
|
||||
this.SubscriptionToolStripMenuItem,
|
||||
this.OptionsToolStripMenuItem,
|
||||
this.HelpToolStripMenuItem,
|
||||
this.exitToolStripMenuItem,
|
||||
this.ForceExitToolStripMenuItem,
|
||||
this.AboutToolStripButton,
|
||||
this.NewVersionLabel,
|
||||
this.VersionLabel});
|
||||
@@ -162,37 +164,38 @@
|
||||
this.CreateRouteTableRuleToolStripMenuItem.Text = "Create Route Table Rule";
|
||||
this.CreateRouteTableRuleToolStripMenuItem.Click += new System.EventHandler(this.createRouteTableModeToolStripMenuItem_Click);
|
||||
//
|
||||
// SubscribeToolStripMenuItem
|
||||
// SubscriptionToolStripMenuItem
|
||||
//
|
||||
this.SubscribeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ManageSubscribeLinksToolStripMenuItem,
|
||||
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);
|
||||
this.SubscribeToolStripMenuItem.Text = "Subscribe";
|
||||
this.SubscriptionToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ManageSubscriptionsToolStripMenuItem,
|
||||
this.UpdateServersToolStripMenuItem});
|
||||
this.SubscriptionToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.SubscriptionToolStripMenuItem.Name = "SubscriptionToolStripMenuItem";
|
||||
this.SubscriptionToolStripMenuItem.Size = new System.Drawing.Size(92, 21);
|
||||
this.SubscriptionToolStripMenuItem.Text = "Subscription";
|
||||
//
|
||||
// ManageSubscribeLinksToolStripMenuItem
|
||||
// ManageSubscriptionsToolStripMenuItem
|
||||
//
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Name = "ManageSubscribeLinksToolStripMenuItem";
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Text = "Manage Subscribe Links";
|
||||
this.ManageSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.ManageSubscribeLinksToolStripMenuItem_Click);
|
||||
this.ManageSubscriptionsToolStripMenuItem.Name = "ManageSubscriptionsToolStripMenuItem";
|
||||
this.ManageSubscriptionsToolStripMenuItem.Size = new System.Drawing.Size(206, 22);
|
||||
this.ManageSubscriptionsToolStripMenuItem.Text = "Manage Subscriptions";
|
||||
this.ManageSubscriptionsToolStripMenuItem.Click += new System.EventHandler(this.ManageSubscriptionLinksToolStripMenuItem_Click);
|
||||
//
|
||||
// UpdateServersFromSubscribeLinksToolStripMenuItem
|
||||
// UpdateServersToolStripMenuItem
|
||||
//
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksToolStripMenuItem";
|
||||
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);
|
||||
this.UpdateServersToolStripMenuItem.Name = "UpdateServersToolStripMenuItem";
|
||||
this.UpdateServersToolStripMenuItem.Size = new System.Drawing.Size(206, 22);
|
||||
this.UpdateServersToolStripMenuItem.Text = "Update Servers";
|
||||
this.UpdateServersToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscriptionLinksToolStripMenuItem_Click);
|
||||
//
|
||||
// OptionsToolStripMenuItem
|
||||
//
|
||||
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.OpenDirectoryToolStripMenuItem,
|
||||
this.ShowHideConsoleToolStripMenuItem,
|
||||
this.CleanDNSCacheToolStripMenuItem,
|
||||
this.UninstallServiceToolStripMenuItem,
|
||||
this.removeNetchFirewallRulesToolStripMenuItem});
|
||||
this.RemoveNetchFirewallRulesToolStripMenuItem});
|
||||
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.OptionsToolStripMenuItem.Name = "OptionsToolStripMenuItem";
|
||||
this.OptionsToolStripMenuItem.Size = new System.Drawing.Size(66, 21);
|
||||
@@ -205,6 +208,13 @@
|
||||
this.OpenDirectoryToolStripMenuItem.Text = "Open Directory";
|
||||
this.OpenDirectoryToolStripMenuItem.Click += new System.EventHandler(this.OpenDirectoryToolStripMenuItem_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);
|
||||
//
|
||||
// CleanDNSCacheToolStripMenuItem
|
||||
//
|
||||
this.CleanDNSCacheToolStripMenuItem.Name = "CleanDNSCacheToolStripMenuItem";
|
||||
@@ -219,43 +229,43 @@
|
||||
this.UninstallServiceToolStripMenuItem.Text = "Uninstall NF Service";
|
||||
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
|
||||
//
|
||||
// removeNetchFirewallRulesToolStripMenuItem
|
||||
// RemoveNetchFirewallRulesToolStripMenuItem
|
||||
//
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Name = "removeNetchFirewallRulesToolStripMenuItem";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Text = "Remove Netch Firewall Rules";
|
||||
this.removeNetchFirewallRulesToolStripMenuItem.Click += new System.EventHandler(this.RemoveNetchFirewallRulesToolStripMenuItem_Click);
|
||||
this.RemoveNetchFirewallRulesToolStripMenuItem.Name = "RemoveNetchFirewallRulesToolStripMenuItem";
|
||||
this.RemoveNetchFirewallRulesToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
|
||||
this.RemoveNetchFirewallRulesToolStripMenuItem.Text = "Remove Netch Firewall Rules";
|
||||
this.RemoveNetchFirewallRulesToolStripMenuItem.Click += new System.EventHandler(this.RemoveNetchFirewallRulesToolStripMenuItem_Click);
|
||||
//
|
||||
// HelpToolStripMenuItem
|
||||
//
|
||||
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.CheckForUpdatesToolStripMenuItem,
|
||||
this.fAQToolStripMenuItem});
|
||||
this.CheckForUpdateToolStripMenuItem,
|
||||
this.FAQToolStripMenuItem});
|
||||
this.HelpToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.HelpToolStripMenuItem.Name = "HelpToolStripMenuItem";
|
||||
this.HelpToolStripMenuItem.Size = new System.Drawing.Size(47, 21);
|
||||
this.HelpToolStripMenuItem.Text = "Help";
|
||||
//
|
||||
// CheckForUpdatesToolStripMenuItem
|
||||
// CheckForUpdateToolStripMenuItem
|
||||
//
|
||||
this.CheckForUpdatesToolStripMenuItem.Name = "CheckForUpdatesToolStripMenuItem";
|
||||
this.CheckForUpdatesToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
|
||||
this.CheckForUpdatesToolStripMenuItem.Text = "Check for updates";
|
||||
this.CheckForUpdatesToolStripMenuItem.Click += new System.EventHandler(this.CheckForUpdatesToolStripMenuItem_Click);
|
||||
this.CheckForUpdateToolStripMenuItem.Name = "CheckForUpdateToolStripMenuItem";
|
||||
this.CheckForUpdateToolStripMenuItem.Size = new System.Drawing.Size(177, 22);
|
||||
this.CheckForUpdateToolStripMenuItem.Text = "Check for update";
|
||||
this.CheckForUpdateToolStripMenuItem.Click += new System.EventHandler(this.CheckForUpdatesToolStripMenuItem_Click);
|
||||
//
|
||||
// fAQToolStripMenuItem
|
||||
// FAQToolStripMenuItem
|
||||
//
|
||||
this.fAQToolStripMenuItem.Name = "fAQToolStripMenuItem";
|
||||
this.fAQToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
|
||||
this.fAQToolStripMenuItem.Text = "FAQ";
|
||||
this.fAQToolStripMenuItem.Click += new System.EventHandler(this.fAQToolStripMenuItem_Click);
|
||||
this.FAQToolStripMenuItem.Name = "FAQToolStripMenuItem";
|
||||
this.FAQToolStripMenuItem.Size = new System.Drawing.Size(177, 22);
|
||||
this.FAQToolStripMenuItem.Text = "FAQ";
|
||||
this.FAQToolStripMenuItem.Click += new System.EventHandler(this.fAQToolStripMenuItem_Click);
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
// ForceExitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(40, 22);
|
||||
this.exitToolStripMenuItem.Text = "Exit";
|
||||
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
|
||||
this.ForceExitToolStripMenuItem.Name = "ForceExitToolStripMenuItem";
|
||||
this.ForceExitToolStripMenuItem.Size = new System.Drawing.Size(40, 22);
|
||||
this.ForceExitToolStripMenuItem.Text = "Exit";
|
||||
this.ForceExitToolStripMenuItem.Click += new System.EventHandler(this.ForceExitToolStripMenuItem_Click);
|
||||
//
|
||||
// AboutToolStripButton
|
||||
//
|
||||
@@ -512,6 +522,7 @@
|
||||
this.DownloadSpeedLabel,
|
||||
this.UploadSpeedLabel,
|
||||
this.blankToolStripStatusLabel,
|
||||
this.HttpStatusLabel,
|
||||
this.NatTypeStatusLabel,
|
||||
this.NatTypeStatusLightLabel});
|
||||
this.StatusStrip.Location = new System.Drawing.Point(0, 272);
|
||||
@@ -554,6 +565,15 @@
|
||||
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(494, 17);
|
||||
this.blankToolStripStatusLabel.Spring = true;
|
||||
//
|
||||
// HttpStatusLabel
|
||||
//
|
||||
this.HttpStatusLabel.Name = "HttpStatusLabel";
|
||||
this.HttpStatusLabel.Size = new System.Drawing.Size(41, 17);
|
||||
this.HttpStatusLabel.Text = "HTTP:";
|
||||
this.HttpStatusLabel.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
|
||||
this.HttpStatusLabel.Visible = false;
|
||||
this.HttpStatusLabel.Click += new System.EventHandler(this.TcpStatusLabel_Click);
|
||||
//
|
||||
// NatTypeStatusLabel
|
||||
//
|
||||
this.NatTypeStatusLabel.Name = "NatTypeStatusLabel";
|
||||
@@ -600,19 +620,19 @@
|
||||
this.ExitToolStripButton});
|
||||
this.NotifyMenu.Name = "NotifyMenu";
|
||||
this.NotifyMenu.ShowItemToolTips = false;
|
||||
this.NotifyMenu.Size = new System.Drawing.Size(108, 48);
|
||||
this.NotifyMenu.Size = new System.Drawing.Size(181, 70);
|
||||
//
|
||||
// ShowMainFormToolStripButton
|
||||
//
|
||||
this.ShowMainFormToolStripButton.Name = "ShowMainFormToolStripButton";
|
||||
this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(107, 22);
|
||||
this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(180, 22);
|
||||
this.ShowMainFormToolStripButton.Text = "Show";
|
||||
this.ShowMainFormToolStripButton.Click += new System.EventHandler(this.ShowMainFormToolStripButton_Click);
|
||||
//
|
||||
// ExitToolStripButton
|
||||
//
|
||||
this.ExitToolStripButton.Name = "ExitToolStripButton";
|
||||
this.ExitToolStripButton.Size = new System.Drawing.Size(107, 22);
|
||||
this.ExitToolStripButton.Size = new System.Drawing.Size(180, 22);
|
||||
this.ExitToolStripButton.Text = "Exit";
|
||||
this.ExitToolStripButton.Click += new System.EventHandler(this.ExitToolStripButton_Click);
|
||||
//
|
||||
@@ -724,7 +744,7 @@
|
||||
|
||||
private System.Windows.Forms.ToolStripMenuItem CreateRouteTableRuleToolStripMenuItem;
|
||||
|
||||
private System.Windows.Forms.ToolStripMenuItem removeNetchFirewallRulesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem RemoveNetchFirewallRulesToolStripMenuItem;
|
||||
|
||||
private System.Windows.Forms.ToolStripButton AboutToolStripButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem CleanDNSCacheToolStripMenuItem;
|
||||
@@ -739,11 +759,11 @@
|
||||
private System.Windows.Forms.PictureBox EditModePictureBox;
|
||||
private System.Windows.Forms.PictureBox EditServerPictureBox;
|
||||
private System.Windows.Forms.ToolStripMenuItem ExitToolStripButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ForceExitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ImportServersFromClipboardToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ManageSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ManageSubscriptionsToolStripMenuItem;
|
||||
private System.Windows.Forms.MenuStrip MenuStrip;
|
||||
private System.Windows.Forms.ComboBox ModeComboBox;
|
||||
public System.Windows.Forms.ComboBox ModeComboBox;
|
||||
private System.Windows.Forms.Label ModeLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem ModeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem HelpToolStripMenuItem;
|
||||
@@ -756,7 +776,7 @@
|
||||
private System.Windows.Forms.Label ProfileLabel;
|
||||
private System.Windows.Forms.TextBox ProfileNameText;
|
||||
private System.Windows.Forms.TableLayoutPanel ProfileTable;
|
||||
private System.Windows.Forms.ToolStripMenuItem CheckForUpdatesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem CheckForUpdateToolStripMenuItem;
|
||||
private System.Windows.Forms.ComboBox ServerComboBox;
|
||||
private System.Windows.Forms.Label ServerLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem ServerToolStripMenuItem;
|
||||
@@ -765,22 +785,24 @@
|
||||
private System.Windows.Forms.PictureBox SpeedPictureBox;
|
||||
private System.Windows.Forms.ToolStripStatusLabel StatusLabel;
|
||||
private System.Windows.Forms.StatusStrip StatusStrip;
|
||||
private System.Windows.Forms.ToolStripMenuItem SubscribeToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SubscriptionToolStripMenuItem;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.ToolStripMenuItem UninstallServiceToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem UpdateServersToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UploadSpeedLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel UsedBandwidthLabel;
|
||||
private System.Windows.Forms.ToolStripLabel NewVersionLabel;
|
||||
private System.Windows.Forms.ToolStripLabel VersionLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel NatTypeStatusLightLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel blankToolStripStatusLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem fAQToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem FAQToolStripMenuItem;
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
|
||||
private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel HttpStatusLabel;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,4 +57,16 @@
|
||||
<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 Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
namespace Netch.Forms.ModeForms
|
||||
{
|
||||
public static class ModeEditorUtils
|
||||
{
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
namespace Netch.Forms.ModeForms
|
||||
{
|
||||
partial class Process
|
||||
partial class ProcessForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -180,7 +180,7 @@ namespace Netch.Forms.Mode
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "Process";
|
||||
this.Name = "ProcessForm";
|
||||
this.Padding = new System.Windows.Forms.Padding(12, 5, 12, 5);
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Create Process Mode";
|
||||
@@ -8,23 +8,24 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
namespace Netch.Forms.ModeForms
|
||||
{
|
||||
public partial class Process : Form
|
||||
public partial class ProcessForm : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// 被编辑的模式
|
||||
/// </summary>
|
||||
private readonly Models.Mode? _mode;
|
||||
private readonly Mode? _mode;
|
||||
|
||||
/// <summary>
|
||||
/// 编辑模式
|
||||
/// </summary>
|
||||
/// <param name="mode">模式</param>
|
||||
public Process(Models.Mode? mode = null)
|
||||
public ProcessForm(Mode? mode = null)
|
||||
{
|
||||
if (mode != null && mode.Type is not 0)
|
||||
if (mode != null && mode.Type is not ModeType.Process)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
InitializeComponent();
|
||||
@@ -62,7 +63,7 @@ namespace Netch.Forms.Mode
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
RuleAddRange(_mode.Rule);
|
||||
RuleAddRange(_mode.Content);
|
||||
}
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
@@ -116,8 +117,8 @@ namespace Netch.Forms.Mode
|
||||
if (_mode != null)
|
||||
{
|
||||
_mode.Remark = RemarkTextBox.Text;
|
||||
_mode.Rule.Clear();
|
||||
_mode.Rule.AddRange(RuleRichTextBox.Lines);
|
||||
_mode.Content.Clear();
|
||||
_mode.Content.AddRange(RuleRichTextBox.Lines);
|
||||
|
||||
_mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
@@ -132,13 +133,13 @@ namespace Netch.Forms.Mode
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = new Models.Mode(fullName)
|
||||
var mode = new Mode(fullName)
|
||||
{
|
||||
Type = 0,
|
||||
Type = ModeType.Process,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(RuleRichTextBox.Lines);
|
||||
mode.Content.AddRange(RuleRichTextBox.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.ComponentModel;
|
||||
using Netch.Properties;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
namespace Netch.Forms.ModeForms
|
||||
{
|
||||
partial class Route
|
||||
partial class RouteForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -166,7 +166,7 @@ namespace Netch.Forms.Mode
|
||||
this.ClientSize = new System.Drawing.Size(356, 419);
|
||||
this.Controls.Add(this.ConfigurationGroupBox);
|
||||
this.Controls.Add(this.ControlButton);
|
||||
this.Name = "Route";
|
||||
this.Name = "RouteForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Create Route Table Rule";
|
||||
this.Load += new System.EventHandler(this.Route_Load);
|
||||
@@ -4,18 +4,20 @@ using Netch.Utils;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Enums;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
namespace Netch.Forms.ModeForms
|
||||
{
|
||||
public partial class Route : Form
|
||||
public partial class RouteForm : Form
|
||||
{
|
||||
private readonly TagItem<int>[] _items = { new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs") };
|
||||
private readonly TagItem<ModeType>[] _items =
|
||||
{ new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") };
|
||||
|
||||
private readonly Models.Mode? _mode;
|
||||
private readonly Mode? _mode;
|
||||
|
||||
public Route(Models.Mode? mode = null)
|
||||
public RouteForm(Mode? mode = null)
|
||||
{
|
||||
if (mode != null && mode.Type is not (1 or 2))
|
||||
if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
_mode = mode;
|
||||
@@ -37,7 +39,7 @@ namespace Netch.Forms.Mode
|
||||
RemarkTextBox.Text = _mode.Remark;
|
||||
comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor
|
||||
FilenameTextBox.Text = _mode.RelativePath;
|
||||
richTextBox1.Lines = _mode.Rule.ToArray();
|
||||
richTextBox1.Lines = _mode.Content.ToArray();
|
||||
}
|
||||
|
||||
i18N.TranslateForm(this);
|
||||
@@ -60,9 +62,9 @@ namespace Netch.Forms.Mode
|
||||
if (_mode != null)
|
||||
{
|
||||
_mode.Remark = RemarkTextBox.Text;
|
||||
_mode.Rule.Clear();
|
||||
_mode.Rule.AddRange(richTextBox1.Lines);
|
||||
_mode.Type = (int)comboBox1.SelectedValue;
|
||||
_mode.Content.Clear();
|
||||
_mode.Content.AddRange(richTextBox1.Lines);
|
||||
_mode.Type = (ModeType)comboBox1.SelectedValue;
|
||||
|
||||
_mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
@@ -77,13 +79,13 @@ namespace Netch.Forms.Mode
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = new Models.Mode(fullName)
|
||||
var mode = new Mode(fullName)
|
||||
{
|
||||
Type = (int)comboBox1.SelectedValue,
|
||||
Type = (ModeType)comboBox1.SelectedValue,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(richTextBox1.Lines);
|
||||
mode.Content.AddRange(richTextBox1.Lines);
|
||||
|
||||
mode.WriteFile();
|
||||
MessageBoxX.Show(i18N.Translate("Mode added successfully"));
|
||||
@@ -1,13 +1,13 @@
|
||||
#nullable disable
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -74,6 +74,8 @@ namespace Netch.Forms
|
||||
AddSaveButton();
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
ConfigurationGroupBox.Enabled = !Server.IsInGroup();
|
||||
|
||||
ConfigurationGroupBox.ResumeLayout(false);
|
||||
ConfigurationGroupBox.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
|
||||
333
Netch/Forms/SettingForm.Designer.cs
generated
333
Netch/Forms/SettingForm.Designer.cs
generated
@@ -36,10 +36,7 @@ namespace Netch.Forms
|
||||
this.PortGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.Socks5PortLabel = new System.Windows.Forms.Label();
|
||||
this.Socks5PortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.HTTPPortLabel = new System.Windows.Forms.Label();
|
||||
this.HTTPPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.AllowDevicesCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ResolveServerHostnameCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ServerPingTypeLabel = new System.Windows.Forms.Label();
|
||||
this.ICMPingRadioBtn = new System.Windows.Forms.RadioButton();
|
||||
this.TCPingRadioBtn = new System.Windows.Forms.RadioButton();
|
||||
@@ -54,14 +51,13 @@ namespace Netch.Forms
|
||||
this.LanguageLabel = new System.Windows.Forms.Label();
|
||||
this.LanguageComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.NFTabPage = new System.Windows.Forms.TabPage();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.ProcessProxyProtocolLabel = new System.Windows.Forms.Label();
|
||||
this.ProcessProxyProtocolComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.ProcessFilterProtocolLabel = new System.Windows.Forms.Label();
|
||||
this.ProcessFilterProtocolComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.FilterICMPCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ICMPDelayLabel = new System.Windows.Forms.Label();
|
||||
this.ICMPDelayTextBox = new System.Windows.Forms.TextBox();
|
||||
this.DNSHijackCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.DNSHijackHostTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ICMPHijackCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ICMPHijackHostTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RedirectorSSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ChildProcessHandleCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.WinTUNTabPage = new System.Windows.Forms.TabPage();
|
||||
this.WinTUNGroupBox = new System.Windows.Forms.GroupBox();
|
||||
@@ -101,22 +97,23 @@ namespace Netch.Forms
|
||||
this.MinimizeWhenStartedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.RunAtStartupCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.CheckUpdateWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.NoSupportDialogCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.CheckBetaUpdateCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UpdateServersWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.AioDNSTabPage = new System.Windows.Forms.TabPage();
|
||||
this.AioDNSRuleRuleLabel = new System.Windows.Forms.Label();
|
||||
this.AioDNSRulePathTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ChinaDNSLabel = new System.Windows.Forms.Label();
|
||||
this.ChinaDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.OtherDNSLabel = new System.Windows.Forms.Label();
|
||||
this.OtherDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
this.AioDNSListenPortLabel = new System.Windows.Forms.Label();
|
||||
this.AioDNSListenPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ControlButton = new System.Windows.Forms.Button();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.DNSHijackLabel = new System.Windows.Forms.Label();
|
||||
this.TabControl.SuspendLayout();
|
||||
this.GeneralTabPage.SuspendLayout();
|
||||
this.PortGroupBox.SuspendLayout();
|
||||
this.NFTabPage.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.WinTUNTabPage.SuspendLayout();
|
||||
this.WinTUNGroupBox.SuspendLayout();
|
||||
this.v2rayTabPage.SuspendLayout();
|
||||
@@ -145,7 +142,6 @@ namespace Netch.Forms
|
||||
//
|
||||
this.GeneralTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.GeneralTabPage.Controls.Add(this.PortGroupBox);
|
||||
this.GeneralTabPage.Controls.Add(this.ResolveServerHostnameCheckBox);
|
||||
this.GeneralTabPage.Controls.Add(this.ServerPingTypeLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.ICMPingRadioBtn);
|
||||
this.GeneralTabPage.Controls.Add(this.TCPingRadioBtn);
|
||||
@@ -170,12 +166,10 @@ namespace Netch.Forms
|
||||
//
|
||||
this.PortGroupBox.Controls.Add(this.Socks5PortLabel);
|
||||
this.PortGroupBox.Controls.Add(this.Socks5PortTextBox);
|
||||
this.PortGroupBox.Controls.Add(this.HTTPPortLabel);
|
||||
this.PortGroupBox.Controls.Add(this.HTTPPortTextBox);
|
||||
this.PortGroupBox.Controls.Add(this.AllowDevicesCheckBox);
|
||||
this.PortGroupBox.Location = new System.Drawing.Point(8, 6);
|
||||
this.PortGroupBox.Name = "PortGroupBox";
|
||||
this.PortGroupBox.Size = new System.Drawing.Size(241, 140);
|
||||
this.PortGroupBox.Size = new System.Drawing.Size(241, 115);
|
||||
this.PortGroupBox.TabIndex = 0;
|
||||
this.PortGroupBox.TabStop = false;
|
||||
this.PortGroupBox.Text = "Local Port";
|
||||
@@ -197,57 +191,30 @@ namespace Netch.Forms
|
||||
this.Socks5PortTextBox.TabIndex = 1;
|
||||
this.Socks5PortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// HTTPPortLabel
|
||||
//
|
||||
this.HTTPPortLabel.AutoSize = true;
|
||||
this.HTTPPortLabel.Location = new System.Drawing.Point(9, 54);
|
||||
this.HTTPPortLabel.Name = "HTTPPortLabel";
|
||||
this.HTTPPortLabel.Size = new System.Drawing.Size(38, 17);
|
||||
this.HTTPPortLabel.TabIndex = 2;
|
||||
this.HTTPPortLabel.Text = "HTTP";
|
||||
//
|
||||
// HTTPPortTextBox
|
||||
//
|
||||
this.HTTPPortTextBox.Location = new System.Drawing.Point(120, 51);
|
||||
this.HTTPPortTextBox.Name = "HTTPPortTextBox";
|
||||
this.HTTPPortTextBox.Size = new System.Drawing.Size(90, 23);
|
||||
this.HTTPPortTextBox.TabIndex = 3;
|
||||
this.HTTPPortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// AllowDevicesCheckBox
|
||||
//
|
||||
this.AllowDevicesCheckBox.AutoSize = true;
|
||||
this.AllowDevicesCheckBox.Location = new System.Drawing.Point(6, 107);
|
||||
this.AllowDevicesCheckBox.Location = new System.Drawing.Point(6, 84);
|
||||
this.AllowDevicesCheckBox.Name = "AllowDevicesCheckBox";
|
||||
this.AllowDevicesCheckBox.Size = new System.Drawing.Size(206, 21);
|
||||
this.AllowDevicesCheckBox.TabIndex = 6;
|
||||
this.AllowDevicesCheckBox.TabIndex = 4;
|
||||
this.AllowDevicesCheckBox.Text = "Allow other Devices to connect";
|
||||
this.AllowDevicesCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.AllowDevicesCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ResolveServerHostnameCheckBox
|
||||
//
|
||||
this.ResolveServerHostnameCheckBox.AutoSize = true;
|
||||
this.ResolveServerHostnameCheckBox.Location = new System.Drawing.Point(267, 15);
|
||||
this.ResolveServerHostnameCheckBox.Name = "ResolveServerHostnameCheckBox";
|
||||
this.ResolveServerHostnameCheckBox.Size = new System.Drawing.Size(176, 21);
|
||||
this.ResolveServerHostnameCheckBox.TabIndex = 1;
|
||||
this.ResolveServerHostnameCheckBox.Text = "Resolve Server Hostname";
|
||||
this.ResolveServerHostnameCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ServerPingTypeLabel
|
||||
//
|
||||
this.ServerPingTypeLabel.AutoSize = true;
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 44);
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 15);
|
||||
this.ServerPingTypeLabel.Name = "ServerPingTypeLabel";
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(98, 17);
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(86, 17);
|
||||
this.ServerPingTypeLabel.TabIndex = 2;
|
||||
this.ServerPingTypeLabel.Text = "ServerPingType";
|
||||
this.ServerPingTypeLabel.Text = "Ping Protocol";
|
||||
//
|
||||
// ICMPingRadioBtn
|
||||
//
|
||||
this.ICMPingRadioBtn.AutoSize = true;
|
||||
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 63);
|
||||
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 34);
|
||||
this.ICMPingRadioBtn.Name = "ICMPingRadioBtn";
|
||||
this.ICMPingRadioBtn.Size = new System.Drawing.Size(75, 21);
|
||||
this.ICMPingRadioBtn.TabIndex = 3;
|
||||
@@ -258,7 +225,7 @@ namespace Netch.Forms
|
||||
// TCPingRadioBtn
|
||||
//
|
||||
this.TCPingRadioBtn.AutoSize = true;
|
||||
this.TCPingRadioBtn.Location = new System.Drawing.Point(366, 64);
|
||||
this.TCPingRadioBtn.Location = new System.Drawing.Point(366, 35);
|
||||
this.TCPingRadioBtn.Name = "TCPingRadioBtn";
|
||||
this.TCPingRadioBtn.Size = new System.Drawing.Size(66, 21);
|
||||
this.TCPingRadioBtn.TabIndex = 4;
|
||||
@@ -269,24 +236,24 @@ namespace Netch.Forms
|
||||
// ProfileCountLabel
|
||||
//
|
||||
this.ProfileCountLabel.AutoSize = true;
|
||||
this.ProfileCountLabel.Location = new System.Drawing.Point(12, 160);
|
||||
this.ProfileCountLabel.Location = new System.Drawing.Point(15, 140);
|
||||
this.ProfileCountLabel.Name = "ProfileCountLabel";
|
||||
this.ProfileCountLabel.Size = new System.Drawing.Size(79, 17);
|
||||
this.ProfileCountLabel.Size = new System.Drawing.Size(83, 17);
|
||||
this.ProfileCountLabel.TabIndex = 5;
|
||||
this.ProfileCountLabel.Text = "ProfileCount";
|
||||
this.ProfileCountLabel.Text = "Profile Count";
|
||||
//
|
||||
// ProfileCountTextBox
|
||||
//
|
||||
this.ProfileCountTextBox.Location = new System.Drawing.Point(120, 157);
|
||||
this.ProfileCountTextBox.Location = new System.Drawing.Point(182, 137);
|
||||
this.ProfileCountTextBox.Name = "ProfileCountTextBox";
|
||||
this.ProfileCountTextBox.Size = new System.Drawing.Size(90, 23);
|
||||
this.ProfileCountTextBox.Size = new System.Drawing.Size(70, 23);
|
||||
this.ProfileCountTextBox.TabIndex = 6;
|
||||
this.ProfileCountTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// DetectionTickLabel
|
||||
//
|
||||
this.DetectionTickLabel.AutoSize = true;
|
||||
this.DetectionTickLabel.Location = new System.Drawing.Point(225, 160);
|
||||
this.DetectionTickLabel.Location = new System.Drawing.Point(15, 170);
|
||||
this.DetectionTickLabel.Name = "DetectionTickLabel";
|
||||
this.DetectionTickLabel.Size = new System.Drawing.Size(117, 17);
|
||||
this.DetectionTickLabel.TabIndex = 7;
|
||||
@@ -294,33 +261,33 @@ namespace Netch.Forms
|
||||
//
|
||||
// DetectionTickTextBox
|
||||
//
|
||||
this.DetectionTickTextBox.Location = new System.Drawing.Point(366, 157);
|
||||
this.DetectionTickTextBox.Location = new System.Drawing.Point(182, 167);
|
||||
this.DetectionTickTextBox.Name = "DetectionTickTextBox";
|
||||
this.DetectionTickTextBox.Size = new System.Drawing.Size(68, 23);
|
||||
this.DetectionTickTextBox.Size = new System.Drawing.Size(70, 23);
|
||||
this.DetectionTickTextBox.TabIndex = 8;
|
||||
this.DetectionTickTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// StartedPingLabel
|
||||
//
|
||||
this.StartedPingLabel.AutoSize = true;
|
||||
this.StartedPingLabel.Location = new System.Drawing.Point(12, 187);
|
||||
this.StartedPingLabel.Location = new System.Drawing.Point(15, 200);
|
||||
this.StartedPingLabel.Name = "StartedPingLabel";
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(126, 17);
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(153, 17);
|
||||
this.StartedPingLabel.TabIndex = 9;
|
||||
this.StartedPingLabel.Text = "Delay test after start";
|
||||
this.StartedPingLabel.Text = "Delay test after start(sec)";
|
||||
//
|
||||
// StartedPingIntervalTextBox
|
||||
//
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(177, 184);
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(182, 197);
|
||||
this.StartedPingIntervalTextBox.Name = "StartedPingIntervalTextBox";
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(68, 23);
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(70, 23);
|
||||
this.StartedPingIntervalTextBox.TabIndex = 10;
|
||||
this.StartedPingIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// STUNServerLabel
|
||||
//
|
||||
this.STUNServerLabel.AutoSize = true;
|
||||
this.STUNServerLabel.Location = new System.Drawing.Point(12, 216);
|
||||
this.STUNServerLabel.Location = new System.Drawing.Point(15, 230);
|
||||
this.STUNServerLabel.Name = "STUNServerLabel";
|
||||
this.STUNServerLabel.Size = new System.Drawing.Size(82, 17);
|
||||
this.STUNServerLabel.TabIndex = 11;
|
||||
@@ -329,34 +296,40 @@ namespace Netch.Forms
|
||||
// STUN_ServerComboBox
|
||||
//
|
||||
this.STUN_ServerComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
|
||||
this.STUN_ServerComboBox.Location = new System.Drawing.Point(120, 213);
|
||||
this.STUN_ServerComboBox.Location = new System.Drawing.Point(182, 227);
|
||||
this.STUN_ServerComboBox.Name = "STUN_ServerComboBox";
|
||||
this.STUN_ServerComboBox.Size = new System.Drawing.Size(314, 25);
|
||||
this.STUN_ServerComboBox.Size = new System.Drawing.Size(264, 25);
|
||||
this.STUN_ServerComboBox.TabIndex = 12;
|
||||
//
|
||||
// LanguageLabel
|
||||
//
|
||||
this.LanguageLabel.AutoSize = true;
|
||||
this.LanguageLabel.Location = new System.Drawing.Point(12, 254);
|
||||
this.LanguageLabel.Location = new System.Drawing.Point(15, 260);
|
||||
this.LanguageLabel.Name = "LanguageLabel";
|
||||
this.LanguageLabel.Size = new System.Drawing.Size(65, 17);
|
||||
this.LanguageLabel.TabIndex = 15;
|
||||
this.LanguageLabel.TabIndex = 13;
|
||||
this.LanguageLabel.Text = "Language";
|
||||
//
|
||||
// LanguageComboBox
|
||||
//
|
||||
this.LanguageComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.LanguageComboBox.FormattingEnabled = true;
|
||||
this.LanguageComboBox.Location = new System.Drawing.Point(120, 251);
|
||||
this.LanguageComboBox.Location = new System.Drawing.Point(182, 257);
|
||||
this.LanguageComboBox.Name = "LanguageComboBox";
|
||||
this.LanguageComboBox.Size = new System.Drawing.Size(121, 25);
|
||||
this.LanguageComboBox.TabIndex = 16;
|
||||
this.LanguageComboBox.Size = new System.Drawing.Size(110, 25);
|
||||
this.LanguageComboBox.TabIndex = 14;
|
||||
//
|
||||
// NFTabPage
|
||||
//
|
||||
this.NFTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
|
||||
this.NFTabPage.Controls.Add(this.groupBox1);
|
||||
this.NFTabPage.Controls.Add(this.RedirectorSSCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.ProcessFilterProtocolLabel);
|
||||
this.NFTabPage.Controls.Add(this.ProcessFilterProtocolComboBox);
|
||||
this.NFTabPage.Controls.Add(this.FilterICMPCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.DNSHijackLabel);
|
||||
this.NFTabPage.Controls.Add(this.ICMPDelayLabel);
|
||||
this.NFTabPage.Controls.Add(this.ICMPDelayTextBox);
|
||||
this.NFTabPage.Controls.Add(this.DNSHijackCheckBox);
|
||||
this.NFTabPage.Controls.Add(this.DNSHijackHostTextBox);
|
||||
this.NFTabPage.Controls.Add(this.ChildProcessHandleCheckBox);
|
||||
this.NFTabPage.Location = new System.Drawing.Point(4, 29);
|
||||
this.NFTabPage.Name = "NFTabPage";
|
||||
@@ -365,96 +338,78 @@ namespace Netch.Forms
|
||||
this.NFTabPage.TabIndex = 1;
|
||||
this.NFTabPage.Text = "Process Mode";
|
||||
//
|
||||
// groupBox1
|
||||
// ProcessFilterProtocolLabel
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.ProcessProxyProtocolLabel);
|
||||
this.groupBox1.Controls.Add(this.ProcessProxyProtocolComboBox);
|
||||
this.groupBox1.Controls.Add(this.DNSHijackCheckBox);
|
||||
this.groupBox1.Controls.Add(this.DNSHijackHostTextBox);
|
||||
this.groupBox1.Controls.Add(this.ICMPHijackCheckBox);
|
||||
this.groupBox1.Controls.Add(this.ICMPHijackHostTextBox);
|
||||
this.groupBox1.Location = new System.Drawing.Point(5, 6);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(450, 117);
|
||||
this.groupBox1.TabIndex = 0;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.ProcessFilterProtocolLabel.AutoSize = true;
|
||||
this.ProcessFilterProtocolLabel.Location = new System.Drawing.Point(30, 20);
|
||||
this.ProcessFilterProtocolLabel.Name = "ProcessFilterProtocolLabel";
|
||||
this.ProcessFilterProtocolLabel.Size = new System.Drawing.Size(89, 17);
|
||||
this.ProcessFilterProtocolLabel.TabIndex = 0;
|
||||
this.ProcessFilterProtocolLabel.Text = "Filter Protocol";
|
||||
//
|
||||
// ProcessProxyProtocolLabel
|
||||
// ProcessFilterProtocolComboBox
|
||||
//
|
||||
this.ProcessProxyProtocolLabel.AutoSize = true;
|
||||
this.ProcessProxyProtocolLabel.Location = new System.Drawing.Point(23, 21);
|
||||
this.ProcessProxyProtocolLabel.Name = "ProcessProxyProtocolLabel";
|
||||
this.ProcessProxyProtocolLabel.Size = new System.Drawing.Size(93, 17);
|
||||
this.ProcessProxyProtocolLabel.TabIndex = 0;
|
||||
this.ProcessProxyProtocolLabel.Text = "Proxy Protocol";
|
||||
this.ProcessFilterProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ProcessFilterProtocolComboBox.FormattingEnabled = true;
|
||||
this.ProcessFilterProtocolComboBox.Location = new System.Drawing.Point(237, 17);
|
||||
this.ProcessFilterProtocolComboBox.Name = "ProcessFilterProtocolComboBox";
|
||||
this.ProcessFilterProtocolComboBox.Size = new System.Drawing.Size(98, 25);
|
||||
this.ProcessFilterProtocolComboBox.TabIndex = 1;
|
||||
//
|
||||
// ProcessProxyProtocolComboBox
|
||||
// FilterICMPCheckBox
|
||||
//
|
||||
this.ProcessProxyProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.ProcessProxyProtocolComboBox.FormattingEnabled = true;
|
||||
this.ProcessProxyProtocolComboBox.Location = new System.Drawing.Point(118, 16);
|
||||
this.ProcessProxyProtocolComboBox.Name = "ProcessProxyProtocolComboBox";
|
||||
this.ProcessProxyProtocolComboBox.Size = new System.Drawing.Size(191, 25);
|
||||
this.ProcessProxyProtocolComboBox.TabIndex = 1;
|
||||
this.FilterICMPCheckBox.AutoSize = true;
|
||||
this.FilterICMPCheckBox.Location = new System.Drawing.Point(15, 50);
|
||||
this.FilterICMPCheckBox.Name = "FilterICMPCheckBox";
|
||||
this.FilterICMPCheckBox.Size = new System.Drawing.Size(90, 21);
|
||||
this.FilterICMPCheckBox.TabIndex = 2;
|
||||
this.FilterICMPCheckBox.Text = "Filter ICMP";
|
||||
this.FilterICMPCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ICMPDelayLabel
|
||||
//
|
||||
this.ICMPDelayLabel.AutoSize = true;
|
||||
this.ICMPDelayLabel.Location = new System.Drawing.Point(65, 80);
|
||||
this.ICMPDelayLabel.Name = "ICMPDelayLabel";
|
||||
this.ICMPDelayLabel.Size = new System.Drawing.Size(100, 17);
|
||||
this.ICMPDelayLabel.TabIndex = 3;
|
||||
this.ICMPDelayLabel.Text = "ICMP Delay(ms)";
|
||||
//
|
||||
// ICMPDelayTextBox
|
||||
//
|
||||
this.ICMPDelayTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.FilterICMPCheckBox, "Checked", true));
|
||||
this.ICMPDelayTextBox.Location = new System.Drawing.Point(237, 77);
|
||||
this.ICMPDelayTextBox.Name = "ICMPDelayTextBox";
|
||||
this.ICMPDelayTextBox.Size = new System.Drawing.Size(98, 23);
|
||||
this.ICMPDelayTextBox.TabIndex = 4;
|
||||
this.ICMPDelayTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// DNSHijackCheckBox
|
||||
//
|
||||
this.DNSHijackCheckBox.AutoSize = true;
|
||||
this.DNSHijackCheckBox.Location = new System.Drawing.Point(6, 51);
|
||||
this.DNSHijackCheckBox.Location = new System.Drawing.Point(15, 110);
|
||||
this.DNSHijackCheckBox.Name = "DNSHijackCheckBox";
|
||||
this.DNSHijackCheckBox.Size = new System.Drawing.Size(196, 21);
|
||||
this.DNSHijackCheckBox.TabIndex = 2;
|
||||
this.DNSHijackCheckBox.Text = "Handle process\'s DNS Hijack";
|
||||
this.DNSHijackCheckBox.Size = new System.Drawing.Size(92, 21);
|
||||
this.DNSHijackCheckBox.TabIndex = 5;
|
||||
this.DNSHijackCheckBox.Text = "DNS Hijack";
|
||||
this.DNSHijackCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// DNSHijackHostTextBox
|
||||
//
|
||||
this.DNSHijackHostTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.DNSHijackCheckBox, "Checked", true));
|
||||
this.DNSHijackHostTextBox.Location = new System.Drawing.Point(253, 46);
|
||||
this.DNSHijackHostTextBox.Location = new System.Drawing.Point(237, 138);
|
||||
this.DNSHijackHostTextBox.Name = "DNSHijackHostTextBox";
|
||||
this.DNSHijackHostTextBox.Size = new System.Drawing.Size(191, 23);
|
||||
this.DNSHijackHostTextBox.TabIndex = 4;
|
||||
this.DNSHijackHostTextBox.TabIndex = 6;
|
||||
this.DNSHijackHostTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// ICMPHijackCheckBox
|
||||
//
|
||||
this.ICMPHijackCheckBox.AutoSize = true;
|
||||
this.ICMPHijackCheckBox.Enabled = false;
|
||||
this.ICMPHijackCheckBox.Location = new System.Drawing.Point(6, 81);
|
||||
this.ICMPHijackCheckBox.Name = "ICMPHijackCheckBox";
|
||||
this.ICMPHijackCheckBox.Size = new System.Drawing.Size(139, 21);
|
||||
this.ICMPHijackCheckBox.TabIndex = 5;
|
||||
this.ICMPHijackCheckBox.Text = "Global ICMP Hijack";
|
||||
this.ICMPHijackCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ICMPHijackHostTextBox
|
||||
//
|
||||
this.ICMPHijackHostTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.ICMPHijackCheckBox, "Checked", true));
|
||||
this.ICMPHijackHostTextBox.Enabled = false;
|
||||
this.ICMPHijackHostTextBox.Location = new System.Drawing.Point(253, 78);
|
||||
this.ICMPHijackHostTextBox.Name = "ICMPHijackHostTextBox";
|
||||
this.ICMPHijackHostTextBox.Size = new System.Drawing.Size(191, 23);
|
||||
this.ICMPHijackHostTextBox.TabIndex = 7;
|
||||
this.ICMPHijackHostTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// RedirectorSSCheckBox
|
||||
//
|
||||
this.RedirectorSSCheckBox.AutoSize = true;
|
||||
this.RedirectorSSCheckBox.Location = new System.Drawing.Point(11, 129);
|
||||
this.RedirectorSSCheckBox.Name = "RedirectorSSCheckBox";
|
||||
this.RedirectorSSCheckBox.Size = new System.Drawing.Size(106, 21);
|
||||
this.RedirectorSSCheckBox.TabIndex = 1;
|
||||
this.RedirectorSSCheckBox.Text = "Redirector SS";
|
||||
this.RedirectorSSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ChildProcessHandleCheckBox
|
||||
//
|
||||
this.ChildProcessHandleCheckBox.AutoSize = true;
|
||||
this.ChildProcessHandleCheckBox.Enabled = false;
|
||||
this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(11, 151);
|
||||
this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(15, 170);
|
||||
this.ChildProcessHandleCheckBox.Name = "ChildProcessHandleCheckBox";
|
||||
this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(150, 21);
|
||||
this.ChildProcessHandleCheckBox.TabIndex = 2;
|
||||
this.ChildProcessHandleCheckBox.TabIndex = 7;
|
||||
this.ChildProcessHandleCheckBox.Text = "Child Process Handle";
|
||||
this.ChildProcessHandleCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
@@ -775,6 +730,7 @@ namespace Netch.Forms
|
||||
this.OtherTabPage.Controls.Add(this.MinimizeWhenStartedCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.RunAtStartupCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.CheckUpdateWhenOpenedCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.NoSupportDialogCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.CheckBetaUpdateCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.UpdateServersWhenOpenedCheckBox);
|
||||
this.OtherTabPage.Location = new System.Drawing.Point(4, 29);
|
||||
@@ -848,13 +804,23 @@ namespace Netch.Forms
|
||||
this.CheckUpdateWhenOpenedCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.CheckUpdateWhenOpenedCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// NoSupportDialogCheckBox
|
||||
//
|
||||
this.NoSupportDialogCheckBox.AutoSize = true;
|
||||
this.NoSupportDialogCheckBox.Location = new System.Drawing.Point(6, 72);
|
||||
this.NoSupportDialogCheckBox.Name = "NoSupportDialogCheckBox";
|
||||
this.NoSupportDialogCheckBox.Size = new System.Drawing.Size(174, 21);
|
||||
this.NoSupportDialogCheckBox.TabIndex = 6;
|
||||
this.NoSupportDialogCheckBox.Text = "Disable Support Warning";
|
||||
this.NoSupportDialogCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// CheckBetaUpdateCheckBox
|
||||
//
|
||||
this.CheckBetaUpdateCheckBox.AutoSize = true;
|
||||
this.CheckBetaUpdateCheckBox.Location = new System.Drawing.Point(200, 72);
|
||||
this.CheckBetaUpdateCheckBox.Name = "CheckBetaUpdateCheckBox";
|
||||
this.CheckBetaUpdateCheckBox.Size = new System.Drawing.Size(137, 21);
|
||||
this.CheckBetaUpdateCheckBox.TabIndex = 6;
|
||||
this.CheckBetaUpdateCheckBox.TabIndex = 7;
|
||||
this.CheckBetaUpdateCheckBox.Text = "Check Beta update";
|
||||
this.CheckBetaUpdateCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.CheckBetaUpdateCheckBox.UseVisualStyleBackColor = true;
|
||||
@@ -865,19 +831,19 @@ namespace Netch.Forms
|
||||
this.UpdateServersWhenOpenedCheckBox.Location = new System.Drawing.Point(200, 94);
|
||||
this.UpdateServersWhenOpenedCheckBox.Name = "UpdateServersWhenOpenedCheckBox";
|
||||
this.UpdateServersWhenOpenedCheckBox.Size = new System.Drawing.Size(200, 21);
|
||||
this.UpdateServersWhenOpenedCheckBox.TabIndex = 7;
|
||||
this.UpdateServersWhenOpenedCheckBox.TabIndex = 8;
|
||||
this.UpdateServersWhenOpenedCheckBox.Text = "Update Servers when opened";
|
||||
this.UpdateServersWhenOpenedCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.UpdateServersWhenOpenedCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// AioDNSTabPage
|
||||
//
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSRuleRuleLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSRulePathTextBox);
|
||||
this.AioDNSTabPage.Controls.Add(this.ChinaDNSLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.ChinaDNSTextBox);
|
||||
this.AioDNSTabPage.Controls.Add(this.OtherDNSLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.OtherDNSTextBox);
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSListenPortLabel);
|
||||
this.AioDNSTabPage.Controls.Add(this.AioDNSListenPortTextBox);
|
||||
this.AioDNSTabPage.Location = new System.Drawing.Point(4, 29);
|
||||
this.AioDNSTabPage.Name = "AioDNSTabPage";
|
||||
this.AioDNSTabPage.Padding = new System.Windows.Forms.Padding(3);
|
||||
@@ -886,57 +852,57 @@ namespace Netch.Forms
|
||||
this.AioDNSTabPage.Text = "AioDNS";
|
||||
this.AioDNSTabPage.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// AioDNSRuleRuleLabel
|
||||
//
|
||||
this.AioDNSRuleRuleLabel.AutoSize = true;
|
||||
this.AioDNSRuleRuleLabel.Location = new System.Drawing.Point(16, 30);
|
||||
this.AioDNSRuleRuleLabel.Name = "AioDNSRuleRuleLabel";
|
||||
this.AioDNSRuleRuleLabel.Size = new System.Drawing.Size(56, 17);
|
||||
this.AioDNSRuleRuleLabel.TabIndex = 0;
|
||||
this.AioDNSRuleRuleLabel.Text = "Rule File";
|
||||
//
|
||||
// AioDNSRulePathTextBox
|
||||
//
|
||||
this.AioDNSRulePathTextBox.Enabled = false;
|
||||
this.AioDNSRulePathTextBox.Location = new System.Drawing.Point(150, 30);
|
||||
this.AioDNSRulePathTextBox.Name = "AioDNSRulePathTextBox";
|
||||
this.AioDNSRulePathTextBox.Size = new System.Drawing.Size(201, 23);
|
||||
this.AioDNSRulePathTextBox.TabIndex = 1;
|
||||
//
|
||||
// ChinaDNSLabel
|
||||
//
|
||||
this.ChinaDNSLabel.AutoSize = true;
|
||||
this.ChinaDNSLabel.Location = new System.Drawing.Point(16, 70);
|
||||
this.ChinaDNSLabel.Location = new System.Drawing.Point(15, 23);
|
||||
this.ChinaDNSLabel.Name = "ChinaDNSLabel";
|
||||
this.ChinaDNSLabel.Size = new System.Drawing.Size(70, 17);
|
||||
this.ChinaDNSLabel.TabIndex = 2;
|
||||
this.ChinaDNSLabel.TabIndex = 0;
|
||||
this.ChinaDNSLabel.Text = "China DNS";
|
||||
//
|
||||
// ChinaDNSTextBox
|
||||
//
|
||||
this.ChinaDNSTextBox.Location = new System.Drawing.Point(150, 70);
|
||||
this.ChinaDNSTextBox.Location = new System.Drawing.Point(150, 20);
|
||||
this.ChinaDNSTextBox.Name = "ChinaDNSTextBox";
|
||||
this.ChinaDNSTextBox.Size = new System.Drawing.Size(201, 23);
|
||||
this.ChinaDNSTextBox.TabIndex = 3;
|
||||
this.ChinaDNSTextBox.TabIndex = 1;
|
||||
this.ChinaDNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// OtherDNSLabel
|
||||
//
|
||||
this.OtherDNSLabel.AutoSize = true;
|
||||
this.OtherDNSLabel.Location = new System.Drawing.Point(16, 110);
|
||||
this.OtherDNSLabel.Location = new System.Drawing.Point(15, 63);
|
||||
this.OtherDNSLabel.Name = "OtherDNSLabel";
|
||||
this.OtherDNSLabel.Size = new System.Drawing.Size(71, 17);
|
||||
this.OtherDNSLabel.TabIndex = 4;
|
||||
this.OtherDNSLabel.TabIndex = 2;
|
||||
this.OtherDNSLabel.Text = "Other DNS";
|
||||
//
|
||||
// OtherDNSTextBox
|
||||
//
|
||||
this.OtherDNSTextBox.Location = new System.Drawing.Point(150, 110);
|
||||
this.OtherDNSTextBox.Location = new System.Drawing.Point(150, 60);
|
||||
this.OtherDNSTextBox.Name = "OtherDNSTextBox";
|
||||
this.OtherDNSTextBox.Size = new System.Drawing.Size(201, 23);
|
||||
this.OtherDNSTextBox.TabIndex = 5;
|
||||
this.OtherDNSTextBox.TabIndex = 3;
|
||||
this.OtherDNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// AioDNSListenPortLabel
|
||||
//
|
||||
this.AioDNSListenPortLabel.AutoSize = true;
|
||||
this.AioDNSListenPortLabel.Location = new System.Drawing.Point(15, 103);
|
||||
this.AioDNSListenPortLabel.Name = "AioDNSListenPortLabel";
|
||||
this.AioDNSListenPortLabel.Size = new System.Drawing.Size(69, 17);
|
||||
this.AioDNSListenPortLabel.TabIndex = 4;
|
||||
this.AioDNSListenPortLabel.Text = "Listen Port";
|
||||
//
|
||||
// AioDNSListenPortTextBox
|
||||
//
|
||||
this.AioDNSListenPortTextBox.Location = new System.Drawing.Point(150, 100);
|
||||
this.AioDNSListenPortTextBox.Name = "AioDNSListenPortTextBox";
|
||||
this.AioDNSListenPortTextBox.Size = new System.Drawing.Size(80, 23);
|
||||
this.AioDNSListenPortTextBox.TabIndex = 5;
|
||||
this.AioDNSListenPortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
@@ -961,6 +927,15 @@ namespace Netch.Forms
|
||||
this.flowLayoutPanel1.Size = new System.Drawing.Size(480, 400);
|
||||
this.flowLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// DNSHijackLabel
|
||||
//
|
||||
this.DNSHijackLabel.AutoSize = true;
|
||||
this.DNSHijackLabel.Location = new System.Drawing.Point(65, 140);
|
||||
this.DNSHijackLabel.Name = "DNSHijackLabel";
|
||||
this.DNSHijackLabel.Size = new System.Drawing.Size(34, 17);
|
||||
this.DNSHijackLabel.TabIndex = 3;
|
||||
this.DNSHijackLabel.Text = "DNS";
|
||||
//
|
||||
// SettingForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
@@ -982,8 +957,6 @@ namespace Netch.Forms
|
||||
this.PortGroupBox.PerformLayout();
|
||||
this.NFTabPage.ResumeLayout(false);
|
||||
this.NFTabPage.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.WinTUNTabPage.ResumeLayout(false);
|
||||
this.WinTUNGroupBox.ResumeLayout(false);
|
||||
this.WinTUNGroupBox.PerformLayout();
|
||||
@@ -1012,11 +985,8 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.TabPage v2rayTabPage;
|
||||
private System.Windows.Forms.GroupBox PortGroupBox;
|
||||
private System.Windows.Forms.CheckBox AllowDevicesCheckBox;
|
||||
private System.Windows.Forms.Label HTTPPortLabel;
|
||||
private System.Windows.Forms.TextBox HTTPPortTextBox;
|
||||
private System.Windows.Forms.Label Socks5PortLabel;
|
||||
private System.Windows.Forms.TextBox Socks5PortTextBox;
|
||||
private System.Windows.Forms.CheckBox ResolveServerHostnameCheckBox;
|
||||
private System.Windows.Forms.GroupBox WinTUNGroupBox;
|
||||
private System.Windows.Forms.CheckBox ProxyDNSCheckBox;
|
||||
private System.Windows.Forms.CheckBox UseCustomDNSCheckBox;
|
||||
@@ -1067,22 +1037,23 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.TextBox ttiTextBox;
|
||||
private System.Windows.Forms.CheckBox UseMuxCheckBox;
|
||||
private System.Windows.Forms.TabPage AioDNSTabPage;
|
||||
private System.Windows.Forms.Label AioDNSRuleRuleLabel;
|
||||
private System.Windows.Forms.TextBox AioDNSRulePathTextBox;
|
||||
private System.Windows.Forms.Label AioDNSListenPortLabel;
|
||||
private System.Windows.Forms.TextBox AioDNSListenPortTextBox;
|
||||
private System.Windows.Forms.Label OtherDNSLabel;
|
||||
private System.Windows.Forms.Label ChinaDNSLabel;
|
||||
private System.Windows.Forms.TextBox OtherDNSTextBox;
|
||||
private System.Windows.Forms.TextBox ChinaDNSTextBox;
|
||||
private System.Windows.Forms.TextBox DNSHijackHostTextBox;
|
||||
private System.Windows.Forms.CheckBox RedirectorSSCheckBox;
|
||||
private System.Windows.Forms.Label ServerPingTypeLabel;
|
||||
private System.Windows.Forms.RadioButton TCPingRadioBtn;
|
||||
private System.Windows.Forms.RadioButton ICMPingRadioBtn;
|
||||
private System.Windows.Forms.ComboBox ProcessProxyProtocolComboBox;
|
||||
private System.Windows.Forms.Label ProcessProxyProtocolLabel;
|
||||
private System.Windows.Forms.CheckBox ICMPHijackCheckBox;
|
||||
private System.Windows.Forms.ComboBox ProcessFilterProtocolComboBox;
|
||||
private System.Windows.Forms.Label ProcessFilterProtocolLabel;
|
||||
private System.Windows.Forms.CheckBox FilterICMPCheckBox;
|
||||
private System.Windows.Forms.CheckBox ChildProcessHandleCheckBox;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.TextBox ICMPHijackHostTextBox;
|
||||
private System.Windows.Forms.TextBox ICMPDelayTextBox;
|
||||
private System.Windows.Forms.Label ICMPDelayLabel;
|
||||
private System.Windows.Forms.CheckBox NoSupportDialogCheckBox;
|
||||
private System.Windows.Forms.Label DNSHijackLabel;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
@@ -8,6 +5,10 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -25,29 +26,19 @@ namespace Netch.Forms
|
||||
|
||||
#region General
|
||||
|
||||
BindTextBox<ushort>(Socks5PortTextBox,
|
||||
p => p.ToString() != HTTPPortTextBox.Text,
|
||||
p => Global.Settings.Socks5LocalPort = p,
|
||||
Global.Settings.Socks5LocalPort);
|
||||
|
||||
BindTextBox<ushort>(HTTPPortTextBox,
|
||||
p => p.ToString() != Socks5PortTextBox.Text,
|
||||
p => Global.Settings.HTTPLocalPort = p,
|
||||
Global.Settings.HTTPLocalPort);
|
||||
BindTextBox<ushort>(Socks5PortTextBox, p => true, p => Global.Settings.Socks5LocalPort = p, Global.Settings.Socks5LocalPort);
|
||||
|
||||
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 });
|
||||
|
||||
BindCheckBox(ResolveServerHostnameCheckBox, c => Global.Settings.ResolveServerHostname = c, Global.Settings.ResolveServerHostname);
|
||||
|
||||
BindRadioBox(ICMPingRadioBtn, _ => { }, !Global.Settings.ServerTCPing);
|
||||
|
||||
BindRadioBox(TCPingRadioBtn, c => Global.Settings.ServerTCPing = c, Global.Settings.ServerTCPing);
|
||||
|
||||
BindTextBox<int>(ProfileCountTextBox, i => i > -1, i => Global.Settings.ProfileCount = i, Global.Settings.ProfileCount);
|
||||
BindTextBox<int>(DetectionTickTextBox,
|
||||
i => ServerHelper.DelayTestHelper.Range.InRange(i),
|
||||
i => DelayTestHelper.Range.InRange(i),
|
||||
i => Global.Settings.DetectionTick = i,
|
||||
Global.Settings.DetectionTick);
|
||||
|
||||
@@ -59,11 +50,11 @@ namespace Netch.Forms
|
||||
object[]? stuns;
|
||||
try
|
||||
{
|
||||
stuns = File.ReadLines("bin\\stun.txt").Cast<object>().ToArray();
|
||||
stuns = File.ReadLines(Constants.STUNServersFile).Cast<object>().ToArray();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Warning($"Load stun.txt failed: {e.Message}");
|
||||
Log.Warning(e, "Load stun.txt failed");
|
||||
stuns = null;
|
||||
}
|
||||
|
||||
@@ -98,28 +89,23 @@ namespace Netch.Forms
|
||||
|
||||
#region Process Mode
|
||||
|
||||
BindListComboBox(ProcessFilterProtocolComboBox,
|
||||
s => Global.Settings.Redirector.FilterProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)),
|
||||
Global.Settings.Redirector.FilterProtocol.ToString());
|
||||
|
||||
BindCheckBox(FilterICMPCheckBox, b => Global.Settings.Redirector.FilterICMP = b, Global.Settings.Redirector.FilterICMP);
|
||||
|
||||
BindTextBox<int>(ICMPDelayTextBox, s => true, s => Global.Settings.Redirector.ICMPDelay = s, Global.Settings.Redirector.ICMPDelay);
|
||||
|
||||
BindCheckBox(DNSHijackCheckBox, b => Global.Settings.Redirector.DNSHijack = b, Global.Settings.Redirector.DNSHijack);
|
||||
|
||||
BindTextBox(DNSHijackHostTextBox, s => true, s => Global.Settings.Redirector.DNSHijackHost = s, Global.Settings.Redirector.DNSHijackHost);
|
||||
|
||||
BindCheckBox(ICMPHijackCheckBox, b => Global.Settings.Redirector.ICMPHijack = b, Global.Settings.Redirector.ICMPHijack);
|
||||
|
||||
BindTextBox(ICMPHijackHostTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.Redirector.ICMPHost = s,
|
||||
Global.Settings.Redirector.ICMPHost);
|
||||
|
||||
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.Redirector.RedirectorSS = s, Global.Settings.Redirector.RedirectorSS);
|
||||
|
||||
BindCheckBox(ChildProcessHandleCheckBox,
|
||||
s => Global.Settings.Redirector.ChildProcessHandle = s,
|
||||
Global.Settings.Redirector.ChildProcessHandle);
|
||||
|
||||
BindListComboBox(ProcessProxyProtocolComboBox,
|
||||
s => Global.Settings.Redirector.ProxyProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
|
||||
Enum.GetNames(typeof(PortType)),
|
||||
Global.Settings.Redirector.ProxyProtocol.ToString());
|
||||
|
||||
#endregion
|
||||
|
||||
#region TUN/TAP
|
||||
@@ -207,16 +193,21 @@ namespace Netch.Forms
|
||||
|
||||
BindCheckBox(UpdateServersWhenOpenedCheckBox, b => Global.Settings.UpdateServersWhenOpened = b, Global.Settings.UpdateServersWhenOpened);
|
||||
|
||||
BindCheckBox(NoSupportDialogCheckBox, b => Global.Settings.NoSupportDialog = b, Global.Settings.NoSupportDialog);
|
||||
|
||||
#endregion
|
||||
|
||||
#region AioDNS
|
||||
|
||||
BindTextBox(AioDNSRulePathTextBox, _ => true, s => Global.Settings.AioDNS.RulePath = s, Global.Settings.AioDNS.RulePath);
|
||||
|
||||
BindTextBox(ChinaDNSTextBox, _ => true, s => Global.Settings.AioDNS.ChinaDNS = s, Global.Settings.AioDNS.ChinaDNS);
|
||||
|
||||
BindTextBox(OtherDNSTextBox, _ => true, s => Global.Settings.AioDNS.OtherDNS = s, Global.Settings.AioDNS.OtherDNS);
|
||||
|
||||
BindTextBox(AioDNSListenPortTextBox,
|
||||
s => ushort.TryParse(s, out _),
|
||||
s => Global.Settings.AioDNS.ListenPort = ushort.Parse(s),
|
||||
Global.Settings.AioDNS.ListenPort);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -240,7 +231,7 @@ namespace Netch.Forms
|
||||
Show();
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
private async void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
|
||||
|
||||
@@ -264,7 +255,7 @@ namespace Netch.Forms
|
||||
|
||||
Utils.Utils.RegisterNetchStartupItem();
|
||||
|
||||
Configuration.Save();
|
||||
await Configuration.SaveAsync();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Forms
|
||||
{
|
||||
partial class SubscribeForm
|
||||
partial class SubscriptionForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -29,24 +29,23 @@
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SubscribeForm));
|
||||
this.AddSubscriptionBox = new System.Windows.Forms.GroupBox();
|
||||
this.RemarkLabel = new System.Windows.Forms.Label();
|
||||
this.RemarkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.LinkLabel = new System.Windows.Forms.Label();
|
||||
this.LinkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.UserAgentLabel = new System.Windows.Forms.Label();
|
||||
this.UserAgentTextBox = new System.Windows.Forms.TextBox();
|
||||
this.UnselectButton = new System.Windows.Forms.Button();
|
||||
this.AddButton = new System.Windows.Forms.Button();
|
||||
this.UserAgentLabel = new System.Windows.Forms.Label();
|
||||
this.LinkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.LinkLabel = new System.Windows.Forms.Label();
|
||||
this.RemarkTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RemarkLabel = new System.Windows.Forms.Label();
|
||||
this.SubscribeLinkListView = new System.Windows.Forms.ListView();
|
||||
this.SubscriptionLinkListView = new System.Windows.Forms.ListView();
|
||||
this.EnableColumnHeader = new System.Windows.Forms.ColumnHeader();
|
||||
this.RemarkColumnHeader = new System.Windows.Forms.ColumnHeader();
|
||||
this.LinkColumnHeader = new System.Windows.Forms.ColumnHeader();
|
||||
this.UserAgentHeader = new System.Windows.Forms.ColumnHeader();
|
||||
this.pContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.deleteServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.DeleteServersToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CopyLinkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MainTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.AddSubscriptionBox.SuspendLayout();
|
||||
@@ -56,14 +55,14 @@
|
||||
//
|
||||
// AddSubscriptionBox
|
||||
//
|
||||
this.AddSubscriptionBox.Controls.Add(this.RemarkLabel);
|
||||
this.AddSubscriptionBox.Controls.Add(this.RemarkTextBox);
|
||||
this.AddSubscriptionBox.Controls.Add(this.LinkLabel);
|
||||
this.AddSubscriptionBox.Controls.Add(this.LinkTextBox);
|
||||
this.AddSubscriptionBox.Controls.Add(this.UserAgentLabel);
|
||||
this.AddSubscriptionBox.Controls.Add(this.UserAgentTextBox);
|
||||
this.AddSubscriptionBox.Controls.Add(this.UnselectButton);
|
||||
this.AddSubscriptionBox.Controls.Add(this.AddButton);
|
||||
this.AddSubscriptionBox.Controls.Add(this.UserAgentLabel);
|
||||
this.AddSubscriptionBox.Controls.Add(this.LinkTextBox);
|
||||
this.AddSubscriptionBox.Controls.Add(this.LinkLabel);
|
||||
this.AddSubscriptionBox.Controls.Add(this.RemarkTextBox);
|
||||
this.AddSubscriptionBox.Controls.Add(this.RemarkLabel);
|
||||
this.AddSubscriptionBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.AddSubscriptionBox.Location = new System.Drawing.Point(8, 248);
|
||||
this.AddSubscriptionBox.Name = "AddSubscriptionBox";
|
||||
@@ -71,6 +70,47 @@
|
||||
this.AddSubscriptionBox.TabIndex = 1;
|
||||
this.AddSubscriptionBox.TabStop = false;
|
||||
//
|
||||
// RemarkLabel
|
||||
//
|
||||
this.RemarkLabel.AutoSize = true;
|
||||
this.RemarkLabel.Location = new System.Drawing.Point(11, 19);
|
||||
this.RemarkLabel.Name = "RemarkLabel";
|
||||
this.RemarkLabel.Size = new System.Drawing.Size(53, 17);
|
||||
this.RemarkLabel.TabIndex = 1;
|
||||
this.RemarkLabel.Text = "Remark";
|
||||
//
|
||||
// RemarkTextBox
|
||||
//
|
||||
this.RemarkTextBox.Location = new System.Drawing.Point(109, 16);
|
||||
this.RemarkTextBox.Name = "RemarkTextBox";
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(545, 23);
|
||||
this.RemarkTextBox.TabIndex = 2;
|
||||
//
|
||||
// LinkLabel
|
||||
//
|
||||
this.LinkLabel.AutoSize = true;
|
||||
this.LinkLabel.Location = new System.Drawing.Point(11, 48);
|
||||
this.LinkLabel.Name = "LinkLabel";
|
||||
this.LinkLabel.Size = new System.Drawing.Size(31, 17);
|
||||
this.LinkLabel.TabIndex = 3;
|
||||
this.LinkLabel.Text = "Link";
|
||||
//
|
||||
// LinkTextBox
|
||||
//
|
||||
this.LinkTextBox.Location = new System.Drawing.Point(109, 45);
|
||||
this.LinkTextBox.Name = "LinkTextBox";
|
||||
this.LinkTextBox.Size = new System.Drawing.Size(545, 23);
|
||||
this.LinkTextBox.TabIndex = 4;
|
||||
//
|
||||
// UserAgentLabel
|
||||
//
|
||||
this.UserAgentLabel.AutoSize = true;
|
||||
this.UserAgentLabel.Location = new System.Drawing.Point(11, 77);
|
||||
this.UserAgentLabel.Name = "UserAgentLabel";
|
||||
this.UserAgentLabel.Size = new System.Drawing.Size(74, 17);
|
||||
this.UserAgentLabel.TabIndex = 5;
|
||||
this.UserAgentLabel.Text = "User-Agent";
|
||||
//
|
||||
// UserAgentTextBox
|
||||
//
|
||||
this.UserAgentTextBox.Location = new System.Drawing.Point(109, 74);
|
||||
@@ -98,68 +138,28 @@
|
||||
this.AddButton.UseVisualStyleBackColor = true;
|
||||
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
|
||||
//
|
||||
// UserAgentLabel
|
||||
// SubscriptionLinkListView
|
||||
//
|
||||
this.UserAgentLabel.AutoSize = true;
|
||||
this.UserAgentLabel.Location = new System.Drawing.Point(11, 77);
|
||||
this.UserAgentLabel.Name = "UserAgentLabel";
|
||||
this.UserAgentLabel.Size = new System.Drawing.Size(74, 17);
|
||||
this.UserAgentLabel.TabIndex = 5;
|
||||
this.UserAgentLabel.Text = "User-Agent";
|
||||
//
|
||||
// LinkTextBox
|
||||
//
|
||||
this.LinkTextBox.Location = new System.Drawing.Point(109, 45);
|
||||
this.LinkTextBox.Name = "LinkTextBox";
|
||||
this.LinkTextBox.Size = new System.Drawing.Size(545, 23);
|
||||
this.LinkTextBox.TabIndex = 4;
|
||||
//
|
||||
// LinkLabel
|
||||
//
|
||||
this.LinkLabel.AutoSize = true;
|
||||
this.LinkLabel.Location = new System.Drawing.Point(11, 48);
|
||||
this.LinkLabel.Name = "LinkLabel";
|
||||
this.LinkLabel.Size = new System.Drawing.Size(31, 17);
|
||||
this.LinkLabel.TabIndex = 3;
|
||||
this.LinkLabel.Text = "Link";
|
||||
//
|
||||
// RemarkTextBox
|
||||
//
|
||||
this.RemarkTextBox.Location = new System.Drawing.Point(109, 16);
|
||||
this.RemarkTextBox.Name = "RemarkTextBox";
|
||||
this.RemarkTextBox.Size = new System.Drawing.Size(545, 23);
|
||||
this.RemarkTextBox.TabIndex = 2;
|
||||
//
|
||||
// RemarkLabel
|
||||
//
|
||||
this.RemarkLabel.AutoSize = true;
|
||||
this.RemarkLabel.Location = new System.Drawing.Point(11, 19);
|
||||
this.RemarkLabel.Name = "RemarkLabel";
|
||||
this.RemarkLabel.Size = new System.Drawing.Size(53, 17);
|
||||
this.RemarkLabel.TabIndex = 1;
|
||||
this.RemarkLabel.Text = "Remark";
|
||||
//
|
||||
// SubscribeLinkListView
|
||||
//
|
||||
this.SubscribeLinkListView.AllowColumnReorder = true;
|
||||
this.SubscribeLinkListView.CheckBoxes = true;
|
||||
this.SubscribeLinkListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[]
|
||||
{
|
||||
this.EnableColumnHeader, this.RemarkColumnHeader, this.LinkColumnHeader, this.UserAgentHeader
|
||||
});
|
||||
this.SubscribeLinkListView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.SubscribeLinkListView.FullRowSelect = true;
|
||||
this.SubscribeLinkListView.HideSelection = false;
|
||||
this.SubscribeLinkListView.Location = new System.Drawing.Point(8, 8);
|
||||
this.SubscribeLinkListView.MultiSelect = false;
|
||||
this.SubscribeLinkListView.Name = "SubscribeLinkListView";
|
||||
this.SubscribeLinkListView.Size = new System.Drawing.Size(668, 234);
|
||||
this.SubscribeLinkListView.TabIndex = 0;
|
||||
this.SubscribeLinkListView.UseCompatibleStateImageBehavior = false;
|
||||
this.SubscribeLinkListView.View = System.Windows.Forms.View.Details;
|
||||
this.SubscribeLinkListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.SubscribeLinkListView_ItemChecked);
|
||||
this.SubscribeLinkListView.SelectedIndexChanged += new System.EventHandler(this.SubscribeLinkListView_SelectedIndexChanged);
|
||||
this.SubscribeLinkListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.SubscribeLinkListView_MouseUp);
|
||||
this.SubscriptionLinkListView.AllowColumnReorder = true;
|
||||
this.SubscriptionLinkListView.CheckBoxes = true;
|
||||
this.SubscriptionLinkListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.EnableColumnHeader,
|
||||
this.RemarkColumnHeader,
|
||||
this.LinkColumnHeader,
|
||||
this.UserAgentHeader});
|
||||
this.SubscriptionLinkListView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.SubscriptionLinkListView.FullRowSelect = true;
|
||||
this.SubscriptionLinkListView.HideSelection = false;
|
||||
this.SubscriptionLinkListView.Location = new System.Drawing.Point(8, 8);
|
||||
this.SubscriptionLinkListView.MultiSelect = false;
|
||||
this.SubscriptionLinkListView.Name = "SubscriptionLinkListView";
|
||||
this.SubscriptionLinkListView.Size = new System.Drawing.Size(668, 234);
|
||||
this.SubscriptionLinkListView.TabIndex = 0;
|
||||
this.SubscriptionLinkListView.UseCompatibleStateImageBehavior = false;
|
||||
this.SubscriptionLinkListView.View = System.Windows.Forms.View.Details;
|
||||
this.SubscriptionLinkListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.SubscriptionLinkListView_ItemChecked);
|
||||
this.SubscriptionLinkListView.SelectedIndexChanged += new System.EventHandler(this.SubscriptionLinkListView_SelectedIndexChanged);
|
||||
this.SubscriptionLinkListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.SubscriptionLinkListView_MouseUp);
|
||||
//
|
||||
// EnableColumnHeader
|
||||
//
|
||||
@@ -182,39 +182,39 @@
|
||||
//
|
||||
// pContextMenuStrip
|
||||
//
|
||||
this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
|
||||
{
|
||||
this.DeleteToolStripMenuItem, this.deleteServerToolStripMenuItem, this.CopyLinkToolStripMenuItem
|
||||
});
|
||||
this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.DeleteToolStripMenuItem,
|
||||
this.DeleteServersToolStripMenuItem,
|
||||
this.CopyLinkToolStripMenuItem});
|
||||
this.pContextMenuStrip.Name = "pContextMenuStrip";
|
||||
this.pContextMenuStrip.Size = new System.Drawing.Size(151, 70);
|
||||
this.pContextMenuStrip.Size = new System.Drawing.Size(161, 70);
|
||||
//
|
||||
// DeleteToolStripMenuItem
|
||||
//
|
||||
this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
|
||||
this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
|
||||
this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(160, 22);
|
||||
this.DeleteToolStripMenuItem.Text = "Delete";
|
||||
this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click);
|
||||
//
|
||||
// deleteServerToolStripMenuItem
|
||||
// DeleteServersToolStripMenuItem
|
||||
//
|
||||
this.deleteServerToolStripMenuItem.Name = "deleteServerToolStripMenuItem";
|
||||
this.deleteServerToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
|
||||
this.deleteServerToolStripMenuItem.Text = "DeleteServer";
|
||||
this.deleteServerToolStripMenuItem.Click += new System.EventHandler(this.deleteServerToolStripMenuItem_Click);
|
||||
this.DeleteServersToolStripMenuItem.Name = "DeleteServersToolStripMenuItem";
|
||||
this.DeleteServersToolStripMenuItem.Size = new System.Drawing.Size(160, 22);
|
||||
this.DeleteServersToolStripMenuItem.Text = "Delete Servers";
|
||||
this.DeleteServersToolStripMenuItem.Click += new System.EventHandler(this.DeleteServersToolStripMenuItem_Click);
|
||||
//
|
||||
// CopyLinkToolStripMenuItem
|
||||
//
|
||||
this.CopyLinkToolStripMenuItem.Name = "CopyLinkToolStripMenuItem";
|
||||
this.CopyLinkToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
|
||||
this.CopyLinkToolStripMenuItem.Text = "CopyLink";
|
||||
this.CopyLinkToolStripMenuItem.Size = new System.Drawing.Size(160, 22);
|
||||
this.CopyLinkToolStripMenuItem.Text = "Copy link";
|
||||
this.CopyLinkToolStripMenuItem.Click += new System.EventHandler(this.CopyLinkToolStripMenuItem_Click);
|
||||
//
|
||||
// MainTableLayoutPanel
|
||||
//
|
||||
this.MainTableLayoutPanel.ColumnCount = 1;
|
||||
this.MainTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.MainTableLayoutPanel.Controls.Add(this.SubscribeLinkListView, 0, 0);
|
||||
this.MainTableLayoutPanel.Controls.Add(this.SubscriptionLinkListView, 0, 0);
|
||||
this.MainTableLayoutPanel.Controls.Add(this.AddSubscriptionBox, 0, 1);
|
||||
this.MainTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.MainTableLayoutPanel.Location = new System.Drawing.Point(0, 0);
|
||||
@@ -227,25 +227,26 @@
|
||||
this.MainTableLayoutPanel.Size = new System.Drawing.Size(684, 391);
|
||||
this.MainTableLayoutPanel.TabIndex = 11;
|
||||
//
|
||||
// SubscribeForm
|
||||
// SubscriptionForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(684, 391);
|
||||
this.Controls.Add(this.MainTableLayoutPanel);
|
||||
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;
|
||||
this.Name = "SubscribeForm";
|
||||
this.Name = "SubscriptionForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Subscribe";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SubscribeForm_FormClosing);
|
||||
this.Text = "Subscription";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SubscriptionForm_FormClosing);
|
||||
this.AddSubscriptionBox.ResumeLayout(false);
|
||||
this.AddSubscriptionBox.PerformLayout();
|
||||
this.pContextMenuStrip.ResumeLayout(false);
|
||||
this.MainTableLayoutPanel.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
private System.Windows.Forms.ColumnHeader EnableColumnHeader;
|
||||
|
||||
@@ -257,7 +258,7 @@
|
||||
private System.Windows.Forms.Label LinkLabel;
|
||||
private System.Windows.Forms.TextBox RemarkTextBox;
|
||||
private System.Windows.Forms.Button AddButton;
|
||||
private System.Windows.Forms.ListView SubscribeLinkListView;
|
||||
private System.Windows.Forms.ListView SubscriptionLinkListView;
|
||||
private System.Windows.Forms.ColumnHeader RemarkColumnHeader;
|
||||
private System.Windows.Forms.ColumnHeader LinkColumnHeader;
|
||||
private System.Windows.Forms.ContextMenuStrip pContextMenuStrip;
|
||||
@@ -269,6 +270,6 @@
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStripMenuItem deleteServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem DeleteServersToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class SubscribeForm : Form
|
||||
public partial class SubscriptionForm : Form
|
||||
{
|
||||
public SubscribeForm()
|
||||
public SubscriptionForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
Icon = Resources.icon;
|
||||
@@ -17,33 +17,33 @@ namespace Netch.Forms
|
||||
i18N.TranslateForm(this);
|
||||
i18N.TranslateForm(pContextMenuStrip);
|
||||
|
||||
InitSubscribeLink();
|
||||
LoadSubscriptionLinks();
|
||||
}
|
||||
|
||||
private int SelectedIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SubscribeLinkListView.MultiSelect)
|
||||
if (SubscriptionLinkListView.MultiSelect)
|
||||
throw new Exception();
|
||||
|
||||
return SubscribeLinkListView.SelectedIndices.Count == 0 ? -1 : SubscribeLinkListView.SelectedIndices[0];
|
||||
return SubscriptionLinkListView.SelectedIndices.Count == 0 ? -1 : SubscriptionLinkListView.SelectedIndices[0];
|
||||
}
|
||||
}
|
||||
|
||||
#region EventHandler
|
||||
|
||||
private void SubscribeLinkListView_MouseUp(object sender, MouseEventArgs e)
|
||||
private void SubscriptionLinkListView_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
if (SelectedIndex != -1)
|
||||
pContextMenuStrip.Show(SubscribeLinkListView, e.Location);
|
||||
pContextMenuStrip.Show(SubscriptionLinkListView, e.Location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中/取消选中
|
||||
/// </summary>
|
||||
private void SubscribeLinkListView_SelectedIndexChanged(object sender, EventArgs e)
|
||||
private void SubscriptionLinkListView_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetEditingGroup(SelectedIndex);
|
||||
}
|
||||
@@ -51,15 +51,15 @@ namespace Netch.Forms
|
||||
/// <summary>
|
||||
/// 订阅启/禁用
|
||||
/// </summary>
|
||||
private void SubscribeLinkListView_ItemChecked(object sender, ItemCheckedEventArgs e)
|
||||
private void SubscriptionLinkListView_ItemChecked(object sender, ItemCheckedEventArgs e)
|
||||
{
|
||||
var index = e.Item.Index;
|
||||
Global.Settings.SubscribeLink[index].Enable = SubscribeLinkListView.Items[index].Checked;
|
||||
Global.Settings.Subscription[index].Enable = SubscriptionLinkListView.Items[index].Checked;
|
||||
}
|
||||
|
||||
private void SubscribeForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
private async void SubscriptionForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
Configuration.Save();
|
||||
await Configuration.SaveAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -94,13 +94,13 @@ namespace Netch.Forms
|
||||
|
||||
if (SelectedIndex == -1)
|
||||
{
|
||||
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
|
||||
if (Global.Settings.Subscription.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
|
||||
{
|
||||
MessageBoxX.Show("Remark Name Duplicate!");
|
||||
MessageBoxX.Show(i18N.Translate("Subscription with the specified remark already exists"));
|
||||
return;
|
||||
}
|
||||
|
||||
Global.Settings.SubscribeLink.Add(new SubscribeLink
|
||||
Global.Settings.Subscription.Add(new Subscription
|
||||
{
|
||||
Enable = true,
|
||||
Remark = RemarkTextBox.Text,
|
||||
@@ -110,7 +110,7 @@ namespace Netch.Forms
|
||||
}
|
||||
else
|
||||
{
|
||||
var subscribeLink = Global.Settings.SubscribeLink[SelectedIndex];
|
||||
var subscribeLink = Global.Settings.Subscription[SelectedIndex];
|
||||
|
||||
RenameServers(subscribeLink.Remark, RemarkTextBox.Text);
|
||||
subscribeLink.Link = LinkTextBox.Text;
|
||||
@@ -118,7 +118,7 @@ namespace Netch.Forms
|
||||
subscribeLink.UserAgent = UserAgentTextBox.Text;
|
||||
}
|
||||
|
||||
InitSubscribeLink();
|
||||
LoadSubscriptionLinks();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -131,24 +131,24 @@ namespace Netch.Forms
|
||||
confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var subscribeLink = Global.Settings.SubscribeLink[SelectedIndex];
|
||||
var subscribeLink = Global.Settings.Subscription[SelectedIndex];
|
||||
DeleteServers(subscribeLink.Remark);
|
||||
Global.Settings.SubscribeLink.Remove(subscribeLink);
|
||||
Global.Settings.Subscription.Remove(subscribeLink);
|
||||
|
||||
InitSubscribeLink();
|
||||
LoadSubscriptionLinks();
|
||||
}
|
||||
|
||||
private void deleteServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private void DeleteServersToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MessageBoxX.Show(i18N.Translate("Confirm deletion?"), confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
DeleteServers(Global.Settings.SubscribeLink[SelectedIndex].Remark);
|
||||
DeleteServers(Global.Settings.Subscription[SelectedIndex].Remark);
|
||||
}
|
||||
|
||||
private void CopyLinkToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Clipboard.SetText(Global.Settings.SubscribeLink[SelectedIndex].Link);
|
||||
Clipboard.SetText(Global.Settings.Subscription[SelectedIndex].Link);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -166,12 +166,12 @@ namespace Netch.Forms
|
||||
server.Group = newGroup;
|
||||
}
|
||||
|
||||
private void InitSubscribeLink()
|
||||
private void LoadSubscriptionLinks()
|
||||
{
|
||||
SubscribeLinkListView.Items.Clear();
|
||||
SubscriptionLinkListView.Items.Clear();
|
||||
|
||||
foreach (var item in Global.Settings.SubscribeLink)
|
||||
SubscribeLinkListView.Items.Add(new ListViewItem(new[]
|
||||
foreach (var item in Global.Settings.Subscription)
|
||||
SubscriptionLinkListView.Items.Add(new ListViewItem(new[]
|
||||
{
|
||||
"",
|
||||
item.Remark,
|
||||
@@ -202,7 +202,7 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
var item = Global.Settings.SubscribeLink[index];
|
||||
var item = Global.Settings.Subscription[index];
|
||||
AddSubscriptionBox.Text = item.Remark;
|
||||
RemarkTextBox.Text = item.Remark;
|
||||
LinkTextBox.Text = item.Link;
|
||||
63
Netch/Forms/SubscriptionForm.resx
Normal file
63
Netch/Forms/SubscriptionForm.resx
Normal file
@@ -0,0 +1,63 @@
|
||||
<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>
|
||||
<metadata name="pContextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -1,12 +1,11 @@
|
||||
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.Text.Json.Serialization;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -34,24 +33,17 @@ namespace Netch
|
||||
{
|
||||
NetchExecutable = Application.ExecutablePath;
|
||||
NetchDir = Application.StartupPath;
|
||||
#if DEBUG
|
||||
Logger = new ConsoleLogger();
|
||||
#else
|
||||
Logger = new FileLogger();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 主窗体的静态实例
|
||||
/// </summary>
|
||||
public static MainForm MainForm => LazyMainForm.Value;
|
||||
|
||||
public static JsonSerializerOptions NewDefaultJsonSerializerOptions => new()
|
||||
public static JsonSerializerOptions NewCustomJsonSerializerOptions() => new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
IgnoreNullValues = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
}
|
||||
|
||||
11
Netch/Interfaces/IController.cs
Normal file
11
Netch/Interfaces/IController.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IController
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public Task StopAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface ILogger
|
||||
{
|
||||
void Info(string text);
|
||||
void Warning(string text);
|
||||
void Error(string text);
|
||||
void Debug(string s);
|
||||
void ShowLog();
|
||||
}
|
||||
}
|
||||
11
Netch/Interfaces/IModeController.cs
Normal file
11
Netch/Interfaces/IModeController.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Servers;
|
||||
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IModeController : IController
|
||||
{
|
||||
public Task StartAsync(Socks5Server server, Mode mode);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using Netch.Models;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Servers;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IServerController : IController
|
||||
{
|
||||
@@ -8,13 +10,7 @@ namespace Netch.Controllers
|
||||
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="s">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public abstract void Start(in Server s, in Mode mode);
|
||||
public Task<Socks5LocalServer> StartAsync(Server s);
|
||||
}
|
||||
|
||||
public static class ServerControllerExtension
|
||||
@@ -1,8 +1,8 @@
|
||||
using Netch.Controllers;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Models
|
||||
namespace Netch.Interfaces
|
||||
{
|
||||
public interface IServerUtil
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
string[] UriScheme { get; }
|
||||
|
||||
public abstract Type ServerType { get; }
|
||||
public Type ServerType { get; }
|
||||
|
||||
public void Edit(Server s);
|
||||
|
||||
@@ -36,9 +36,9 @@ namespace Netch.Models
|
||||
|
||||
string GetShareLink(Server s);
|
||||
|
||||
public abstract IServerController GetController();
|
||||
public IServerController GetController();
|
||||
|
||||
public abstract IEnumerable<Server> ParseUri(string text);
|
||||
public IEnumerable<Server> ParseUri(string text);
|
||||
|
||||
bool CheckServer(Server s);
|
||||
}
|
||||
@@ -1,17 +1,30 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class AioDNSInterops
|
||||
public static class AioDNS
|
||||
{
|
||||
private const string aiodns_bin = "aiodns.bin";
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Log.Verbose($"[aiodns] Dial {name}: {value}");
|
||||
return aiodns_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public static async Task<bool> InitAsync()
|
||||
{
|
||||
return await Task.Run(Init).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task FreeAsync()
|
||||
{
|
||||
await Task.Run(Free).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[DllImport(aiodns_bin, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool aiodns_dial(NameList name, byte[] value);
|
||||
|
||||
@@ -1,63 +1,52 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class RedirectorInterop
|
||||
public static class Redirector
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERICMP,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
AIO_FILTERLOOPBACK,
|
||||
AIO_FILTERINTRANET, // LAN
|
||||
AIO_FILTERPARENT,
|
||||
AIO_FILTERICMP,
|
||||
AIO_FILTERTCP,
|
||||
AIO_FILTERUDP,
|
||||
AIO_FILTERDNS,
|
||||
|
||||
TYPE_CLRNAME,
|
||||
TYPE_ADDNAME,
|
||||
TYPE_BYPNAME,
|
||||
AIO_ICMPING,
|
||||
|
||||
TYPE_DNSHOST,
|
||||
AIO_DNSHOST,
|
||||
AIO_DNSPORT,
|
||||
|
||||
TYPE_TCPLISN,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
AIO_TGTHOST,
|
||||
AIO_TGTPORT,
|
||||
AIO_TGTUSER,
|
||||
AIO_TGTPASS,
|
||||
|
||||
TYPE_UDPLISN,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
AIO_CLRNAME,
|
||||
AIO_ADDNAME,
|
||||
AIO_BYPNAME
|
||||
}
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Global.Logger.Debug($"Dial {name} {value}");
|
||||
Log.Verbose($"[Redirector] Dial {name}: {value}");
|
||||
return aio_dial(name, value);
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
public static async Task<bool> InitAsync()
|
||||
{
|
||||
return aio_init();
|
||||
return await Task.Run(aio_init).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool Free()
|
||||
public static async Task<bool> FreeAsync()
|
||||
{
|
||||
return aio_free();
|
||||
return await Task.Run(aio_free).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
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)]
|
||||
@@ -69,10 +58,12 @@ namespace Netch.Interops
|
||||
[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);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Interops
|
||||
{
|
||||
public static class TUNInterop
|
||||
public static class tun2socks
|
||||
{
|
||||
public enum NameList
|
||||
{
|
||||
@@ -35,18 +37,19 @@ namespace Netch.Interops
|
||||
|
||||
public static bool Dial(NameList name, string value)
|
||||
{
|
||||
Global.Logger.Debug($"Dial {name} {value}");
|
||||
Log.Verbose( $"[tun2socks] Dial {name}: {value}");
|
||||
return tun_dial(name, Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
{
|
||||
Log.Verbose("[tun2socks] init");
|
||||
return tun_init();
|
||||
}
|
||||
|
||||
public static bool Free()
|
||||
public static async Task<bool> FreeAsync()
|
||||
{
|
||||
return tun_free();
|
||||
return await Task.Run(tun_free).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private const string tun2socks_bin = "tun2socks.bin";
|
||||
@@ -1,9 +1,10 @@
|
||||
using Netch.Models;
|
||||
using System;
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Utils
|
||||
namespace Netch.JsonConverter
|
||||
{
|
||||
public class ServerConverterWithTypeDiscriminator : JsonConverter<Server>
|
||||
{
|
||||
@@ -11,18 +12,9 @@ namespace Netch.Utils
|
||||
|
||||
public override Server Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var jsonElement = JsonSerializer.Deserialize<JsonElement>(ref reader)!;
|
||||
|
||||
try
|
||||
{
|
||||
var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!);
|
||||
return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Unsupported Server Type
|
||||
return JsonSerializer.Deserialize<Server>(jsonElement.GetRawText(), new JsonSerializerOptions())!;
|
||||
}
|
||||
var jsonElement = JsonSerializer.Deserialize<JsonElement>(ref reader);
|
||||
var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!);
|
||||
return (Server)jsonElement.Deserialize(type)!;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, Server value, JsonSerializerOptions options)
|
||||
49
Netch/Models/Arguments.cs
Normal file
49
Netch/Models/Arguments.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public static class Arguments
|
||||
{
|
||||
public static string Format(IEnumerable<object?> a)
|
||||
{
|
||||
var arguments = a.ToList();
|
||||
if (arguments.Count % 2 != 0)
|
||||
throw new FormatException("missing last argument value");
|
||||
|
||||
var tokens = new List<string>();
|
||||
|
||||
for (var i = 0; i < arguments.Count; i += 2)
|
||||
{
|
||||
var keyObj = arguments[i];
|
||||
var valueObj = arguments[i + 1];
|
||||
|
||||
if (keyObj is not string key)
|
||||
throw new FormatException($"argument key at array index {i} is not string");
|
||||
|
||||
switch (valueObj)
|
||||
{
|
||||
case SpecialArgument.Flag:
|
||||
tokens.Add(key);
|
||||
break;
|
||||
case null:
|
||||
case string value when value.IsNullOrWhiteSpace():
|
||||
continue;
|
||||
default:
|
||||
tokens.Add(key);
|
||||
tokens.Add(valueObj.ToString()!);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(' ', tokens);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpecialArgument
|
||||
{
|
||||
Flag
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ namespace Netch.Models.GitHubRelease
|
||||
if (versionComparison != 0)
|
||||
return versionComparison;
|
||||
|
||||
var suffixExistComparison = (Suffix != null ? 1 : 0) - (other.Suffix != null ? 1 : 0);
|
||||
var suffixExistComparison = (Suffix == null ? 1 : 0) - (other.Suffix == null ? 1 : 0);
|
||||
if (suffixExistComparison != 0)
|
||||
return suffixExistComparison;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.GitHubRelease
|
||||
{
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public interface IAdapter
|
||||
{
|
||||
ulong InterfaceIndex { get; }
|
||||
|
||||
IPAddress Gateway { get; }
|
||||
|
||||
NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,168 +1,123 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Enums;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class Mode
|
||||
{
|
||||
private readonly Lazy<List<string>> _lazyRule;
|
||||
|
||||
public string? FullName { get; private set; }
|
||||
private List<string>? _content;
|
||||
|
||||
public Mode(string? fullName)
|
||||
{
|
||||
_lazyRule = new Lazy<List<string>>(ReadRules);
|
||||
if (fullName == null)
|
||||
return;
|
||||
|
||||
FullName = fullName;
|
||||
if (!File.Exists(FullName))
|
||||
if (FullName == null || !File.Exists(FullName))
|
||||
return;
|
||||
|
||||
var text = File.ReadLines(FullName).First();
|
||||
|
||||
// load head
|
||||
if (text.First() != '#')
|
||||
throw new Exception($"mode {FullName} head not found at Line 0");
|
||||
|
||||
var split = text.Substring(1).SplitTrimEntries(',');
|
||||
Remark = split[0];
|
||||
|
||||
var typeResult = int.TryParse(split.ElementAtOrDefault(1), out var type);
|
||||
Type = typeResult ? type : 0;
|
||||
if (!ModeHelper.ModeTypes.Contains(Type))
|
||||
throw new NotSupportedException($"not support mode \"[{Type}]{Remark}\".");
|
||||
Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 规则
|
||||
/// </summary>
|
||||
public List<string> Rule => _lazyRule.Value;
|
||||
public string? FullName { get; }
|
||||
|
||||
public List<string> Content => _content ??= ReadContent();
|
||||
|
||||
/// <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
|
||||
private void Load()
|
||||
{
|
||||
get
|
||||
if (FullName == null)
|
||||
return;
|
||||
|
||||
(Remark, Type) = ReadHead(FullName);
|
||||
_content = null;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetRules()
|
||||
{
|
||||
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);
|
||||
}
|
||||
foreach (var rule in mode.GetRules())
|
||||
yield return rule;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return s;
|
||||
}
|
||||
|
||||
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 strings = text[1..].SplitTrimEntries(',');
|
||||
|
||||
var remark = strings[0];
|
||||
var typeNumber = int.TryParse(strings.ElementAtOrDefault(1), out var type) ? type : 0;
|
||||
|
||||
if (!Enum.GetValues(typeof(ModeType)).Cast<int>().Contains(typeNumber))
|
||||
throw new NotSupportedException($"Not support mode \"{typeNumber}\".");
|
||||
|
||||
return (remark, (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 WriteFile()
|
||||
{
|
||||
if (fullName != null)
|
||||
throw new NotImplementedException();
|
||||
|
||||
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>
|
||||
/// 获取备注
|
||||
/// </summary>
|
||||
/// <returns>备注</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{Type + 1}] {i18N.Translate(Remark)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模式文件字符串
|
||||
/// </summary>
|
||||
/// <returns>模式文件字符串</returns>
|
||||
public string ToFileString()
|
||||
{
|
||||
return $"# {Remark}, {Type}{Constants.EOF}{string.Join(Constants.EOF, Rule)}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ModeExtension
|
||||
{
|
||||
/// 是否会转发 UDP
|
||||
public static bool TestNatRequired(this Mode mode)
|
||||
{
|
||||
return mode.Type is 0 or 2;
|
||||
return $"[{(int)Type + 1}] {i18N.Translate(Remark)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Netch/Models/NatTypeTestResult.cs
Normal file
9
Netch/Models/NatTypeTestResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public struct NatTypeTestResult
|
||||
{
|
||||
public string? Result;
|
||||
public string? LocalEnd;
|
||||
public string? PublicEnd;
|
||||
}
|
||||
}
|
||||
49
Netch/Models/NetRoute.cs
Normal file
49
Netch/Models/NetRoute.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Windows.Win32;
|
||||
|
||||
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 GetBestRouteTemplate()
|
||||
{
|
||||
if (PInvoke.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var route) != 0)
|
||||
throw new MessageException("GetBestRoute 搜索失败");
|
||||
|
||||
var gateway = new IPAddress(route.dwForwardNextHop);
|
||||
return TemplateBuilder(gateway.ToString(), (int)route.dwForwardIfIndex);
|
||||
}
|
||||
|
||||
public int InterfaceIndex;
|
||||
|
||||
public string Gateway;
|
||||
|
||||
public string Network;
|
||||
|
||||
public byte Cidr;
|
||||
|
||||
public int Metric;
|
||||
|
||||
public NetRoute FillTemplate(string network, byte cidr, int? metric = null)
|
||||
{
|
||||
var o = (NetRoute)MemberwiseClone();
|
||||
o.Network = network;
|
||||
o.Cidr = cidr;
|
||||
if (metric != null)
|
||||
o.Metric = (int)metric;
|
||||
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public readonly struct Range
|
||||
public readonly struct NumberRange
|
||||
{
|
||||
public int Start { get; }
|
||||
|
||||
public int End { get; }
|
||||
|
||||
public Range(int start, int end)
|
||||
public NumberRange(int start, int end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class OutboundAdapter : IAdapter
|
||||
{
|
||||
public OutboundAdapter()
|
||||
{
|
||||
// 寻找出口适配器
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0)
|
||||
{
|
||||
throw new MessageException("GetBestRoute 搜索失败");
|
||||
}
|
||||
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.First(ni => ni.Supports(NetworkInterfaceComponent.IPv4) &&
|
||||
ni.GetIPProperties().GetIPv4Properties().Index == pRoute.dwForwardIfIndex);
|
||||
|
||||
Address = new IPAddress(pRoute.dwForwardNextHop.S_addr);
|
||||
InterfaceIndex = (ulong)pRoute.dwForwardIfIndex;
|
||||
Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
|
||||
|
||||
Global.Logger.Info($"出口 网关 地址:{Gateway}");
|
||||
Global.Logger.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
|
||||
}
|
||||
|
||||
public IPAddress Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public ulong InterfaceIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public abstract class ParameterBase
|
||||
{
|
||||
// null value par
|
||||
|
||||
private readonly bool _full;
|
||||
|
||||
protected readonly string ParametersSeparate = " ";
|
||||
protected readonly string Separate = " ";
|
||||
protected readonly string VerbPrefix = "-";
|
||||
protected readonly string FullPrefix = "--";
|
||||
|
||||
protected ParameterBase()
|
||||
{
|
||||
_full = !GetType().IsDefined(typeof(VerbAttribute));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var parameters = GetType().GetProperties().Select(PropToParameter).Where(s => s != null).Cast<string>();
|
||||
return string.Join(ParametersSeparate, parameters).Trim();
|
||||
}
|
||||
|
||||
private string? PropToParameter(PropertyInfo p)
|
||||
{
|
||||
// prefix
|
||||
bool full;
|
||||
if (p.IsDefined(typeof(VerbAttribute)))
|
||||
full = false;
|
||||
else if (p.IsDefined(typeof(FullAttribute)))
|
||||
full = true;
|
||||
else
|
||||
full = _full;
|
||||
|
||||
var prefix = full ? FullPrefix : VerbPrefix;
|
||||
// key
|
||||
var key = p.GetCustomAttribute<RealNameAttribute>()?.Name ?? p.Name;
|
||||
|
||||
// build
|
||||
var value = p.GetValue(this);
|
||||
switch (value)
|
||||
{
|
||||
case bool b:
|
||||
return b ? $"{prefix}{key}" : null;
|
||||
default:
|
||||
if (string.IsNullOrWhiteSpace(value?.ToString()))
|
||||
return p.IsDefined(typeof(OptionalAttribute)) ? null : throw new RequiredArgumentValueInvalidException(p.Name, this, null);
|
||||
|
||||
if (p.IsDefined(typeof(QuoteAttribute)))
|
||||
value = $"\"{value}\"";
|
||||
|
||||
return $"{prefix}{key}{Separate}{value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
|
||||
public class VerbAttribute : Attribute
|
||||
{
|
||||
// Don't use verb and full both on one class or property
|
||||
// if you did, will take verb
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
|
||||
public class FullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class OptionalAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class QuoteAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class RealNameAttribute : Attribute
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public RealNameAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RequiredArgumentValueInvalidException : Exception
|
||||
{
|
||||
public string? ArgumentName { get; }
|
||||
|
||||
public object? ArgumentObject { get; }
|
||||
|
||||
private readonly string? _message;
|
||||
|
||||
private const string DefaultMessage = "{0}'s Argument \"{1}\" value invalid. A required argument's value can't be null or empty.";
|
||||
|
||||
public override string Message => _message ?? string.Format(DefaultMessage, ArgumentObject!.GetType(), ArgumentName);
|
||||
|
||||
public RequiredArgumentValueInvalidException()
|
||||
{
|
||||
_message = "Some Argument value invalid. A required argument value's can't be null or empty.";
|
||||
}
|
||||
|
||||
public RequiredArgumentValueInvalidException(string argumentName, object argumentObject, string? message)
|
||||
{
|
||||
ArgumentName = argumentName;
|
||||
ArgumentObject = argumentObject;
|
||||
_message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class Server : ICloneable
|
||||
public abstract class Server : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// 延迟
|
||||
@@ -17,7 +17,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 组
|
||||
/// </summary>
|
||||
public string Group { get; set; } = "None";
|
||||
public string Group { get; set; } = Constants.DefaultGroup;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
@@ -42,11 +42,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 代理类型
|
||||
/// </summary>
|
||||
public virtual string Type { get; } = string.Empty;
|
||||
|
||||
[JsonExtensionData]
|
||||
// ReSharper disable once CollectionNeverUpdated.Global
|
||||
public Dictionary<string, object> ExtensionData { get; set; } = new();
|
||||
public abstract string Type { get; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
@@ -61,55 +57,48 @@ namespace Netch.Models
|
||||
{
|
||||
var remark = string.IsNullOrWhiteSpace(Remark) ? $"{Hostname}:{Port}" : Remark;
|
||||
|
||||
if (Group.Equals("None") || Group.Equals(""))
|
||||
Group = "NONE";
|
||||
|
||||
string shortName;
|
||||
if (Type == string.Empty)
|
||||
{
|
||||
shortName = "WTF";
|
||||
}
|
||||
else
|
||||
{
|
||||
shortName = ServerHelper.GetUtilByTypeName(Type).ShortName;
|
||||
}
|
||||
var shortName = ServerHelper.GetUtilByTypeName(Type).ShortName;
|
||||
|
||||
return $"[{shortName}][{Group}] {remark}";
|
||||
}
|
||||
|
||||
public abstract string MaskedData();
|
||||
|
||||
/// <summary>
|
||||
/// 测试延迟
|
||||
/// </summary>
|
||||
/// <returns>延迟</returns>
|
||||
public int Test()
|
||||
public async Task<int> PingAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var destination = DnsUtils.Lookup(Hostname);
|
||||
var destination = await DnsUtils.LookupAsync(Hostname);
|
||||
if (destination == null)
|
||||
return Delay = -2;
|
||||
|
||||
var list = new Task<int>[3];
|
||||
for (var i = 0; i < 3; i++)
|
||||
list[i] = Task.Run(async () =>
|
||||
{
|
||||
async Task<int> PingCoreAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Global.Settings.ServerTCPing
|
||||
? await Utils.Utils.TCPingAsync(destination, Port)
|
||||
: Utils.Utils.ICMPing(destination, Port);
|
||||
: await Utils.Utils.ICMPingAsync(destination);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Task.WaitAll(list[0], list[1], list[2]);
|
||||
list[i] = PingCoreAsync();
|
||||
}
|
||||
|
||||
var min = Math.Min(list[0].Result, list[1].Result);
|
||||
min = Math.Min(min, list[2].Result);
|
||||
return Delay = min;
|
||||
var resTask = await Task.WhenAny(list[0], list[1], list[2]);
|
||||
|
||||
return Delay = await resTask;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -120,22 +109,15 @@ namespace Netch.Models
|
||||
|
||||
public static class ServerExtension
|
||||
{
|
||||
public static string AutoResolveHostname(this Server server)
|
||||
public static async Task<string> AutoResolveHostnameAsync(this Server server, AddressFamily inet = AddressFamily.Unspecified)
|
||||
{
|
||||
return Global.Settings.ResolveServerHostname ? DnsUtils.Lookup(server.Hostname)!.ToString() : server.Hostname;
|
||||
// ! MainController cached
|
||||
return (await DnsUtils.LookupAsync(server.Hostname, inet))!.ToString();
|
||||
}
|
||||
|
||||
public static bool Valid(this Server server)
|
||||
public static bool IsInGroup(this Server server)
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerHelper.GetTypeByTypeName(server.Type);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return server.Group is not Constants.DefaultGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -36,7 +39,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 使用自定义 DNS 设置
|
||||
/// </summary>
|
||||
public bool UseCustomDNS { get; set; } = true;
|
||||
public bool UseCustomDNS { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 全局绕过 IP 列表
|
||||
@@ -71,7 +74,7 @@ namespace Netch.Models
|
||||
|
||||
public bool V2rayNShareLink { get; set; } = true;
|
||||
|
||||
public bool XrayCone { get; set; } = false;
|
||||
public bool XrayCone { get; set; } = true;
|
||||
}
|
||||
|
||||
public class AioDNSConfig
|
||||
@@ -80,9 +83,7 @@ namespace Netch.Models
|
||||
|
||||
public string OtherDNS { get; set; } = "tcp://1.1.1.1:53";
|
||||
|
||||
public ushort ListenPort { get; set; } = 53;
|
||||
|
||||
public string RulePath { get; set; } = "bin\\aiodns.conf";
|
||||
public ushort ListenPort { get; set; } = 253;
|
||||
}
|
||||
|
||||
public class RedirectorConfig
|
||||
@@ -90,7 +91,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public PortType ProxyProtocol { get; set; } = PortType.Both;
|
||||
public PortType FilterProtocol { get; set; } = PortType.Both;
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启DNS转发
|
||||
@@ -102,14 +103,9 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public string DNSHijackHost { get; set; } = "1.1.1.1:53";
|
||||
|
||||
public string ICMPHost { get; set; } = "1.2.4.8";
|
||||
public int ICMPDelay { get; set; } = 0;
|
||||
|
||||
public bool ICMPHijack { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用RDR内置SS
|
||||
/// </summary>
|
||||
public bool RedirectorSS { get; set; } = false;
|
||||
public bool FilterICMP { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否代理子进程
|
||||
@@ -196,11 +192,6 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public int RequestTimeout { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// 解析服务器主机名
|
||||
/// </summary>
|
||||
public bool ResolveServerHostname { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否开机启动软件
|
||||
/// </summary>
|
||||
@@ -249,7 +240,7 @@ namespace Netch.Models
|
||||
/// <summary>
|
||||
/// 订阅链接列表
|
||||
/// </summary>
|
||||
public List<SubscribeLink> SubscribeLink { get; set; } = new();
|
||||
public List<Subscription> Subscription { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// TUNTAP 适配器配置
|
||||
@@ -263,7 +254,23 @@ namespace Netch.Models
|
||||
|
||||
public V2rayConfig V2RayConfig { get; set; } = new();
|
||||
|
||||
public Setting Clone()
|
||||
public bool NoSupportDialog { get; set; } = false;
|
||||
|
||||
#region Migration
|
||||
|
||||
[Obsolete]
|
||||
public JsonElement SubscribeLink
|
||||
{
|
||||
set
|
||||
{
|
||||
if (Subscription == null! || !Subscription.Any())
|
||||
Subscription = value.Deserialize<List<Subscription>>()!;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Setting ShallowCopy()
|
||||
{
|
||||
return (Setting)MemberwiseClone();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class SubscribeLink
|
||||
public class Subscription
|
||||
{
|
||||
/// <summary>
|
||||
/// 启用状态
|
||||
@@ -1,26 +0,0 @@
|
||||
using Netch.Interops;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class TunAdapter : IAdapter
|
||||
{
|
||||
public TunAdapter()
|
||||
{
|
||||
InterfaceIndex = NativeMethods.ConvertLuidToIndex(TUNInterop.tun_luid());
|
||||
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.GetIPProperties().GetIPv4Properties().Index == (int)InterfaceIndex);
|
||||
Gateway = IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
|
||||
|
||||
Global.Logger.Info($"WinTUN 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
|
||||
}
|
||||
|
||||
|
||||
public ulong InterfaceIndex { get; }
|
||||
|
||||
public IPAddress Gateway { get; }
|
||||
|
||||
public NetworkInterface NetworkInterface { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -7,23 +6,5 @@ namespace Netch
|
||||
{
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint RefreshDNSCache();
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong ConvertLuidToIndex(ulong id);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateIPv4(string address, string netmask, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool RefreshIPTable(AddressFamily inet, ulong index);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
||||
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool DeleteRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
||||
}
|
||||
}
|
||||
|
||||
21
Netch/NativeMethods.txt
Normal file
21
Netch/NativeMethods.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
// IpHlpApi.dll
|
||||
GetBestRoute
|
||||
GetExtendedTcpTable
|
||||
MIB_TCPTABLE_OWNER_PID
|
||||
ADDRESS_FAMILY
|
||||
|
||||
// User32.dll
|
||||
SetWindowPos
|
||||
GetWindowLong
|
||||
ShowWindow
|
||||
WINDOW_STYLE
|
||||
|
||||
// Kernel32.dll
|
||||
AllocConsole
|
||||
GetConsoleWindow
|
||||
|
||||
// Ws2_32.dll
|
||||
ntohs
|
||||
|
||||
// Windows.h
|
||||
// WIN32_ERROR
|
||||
153
Netch/Netch.cs
153
Netch/Netch.cs
@@ -1,20 +1,35 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using static Vanara.PInvoke.Kernel32;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Netch.Controllers;
|
||||
using Netch.Enums;
|
||||
using Netch.Forms;
|
||||
using Netch.Services;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using SingleInstance;
|
||||
#if RELEASE
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
#endif
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public static class Netch
|
||||
{
|
||||
public static readonly SingleInstance.SingleInstance SingleInstance = new($"Global\\{nameof(Netch)}");
|
||||
public static readonly SingleInstanceService SingleInstance = new($"Global\\{nameof(Netch)}");
|
||||
|
||||
internal static HWND ConsoleHwnd { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点
|
||||
@@ -22,13 +37,6 @@ namespace Netch
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
#if DEBUG
|
||||
AttachAllocConsole();
|
||||
#else
|
||||
if (args.Contains(Constants.Parameter.Console))
|
||||
AttachAllocConsole();
|
||||
#endif
|
||||
|
||||
if (args.Contains(Constants.Parameter.ForceUpdate))
|
||||
Flags.AlwaysShowNewVersionFound = true;
|
||||
|
||||
@@ -36,9 +44,15 @@ namespace Netch
|
||||
Directory.SetCurrentDirectory(Global.NetchDir);
|
||||
var binPath = Path.Combine(Global.NetchDir, "bin");
|
||||
Environment.SetEnvironmentVariable("PATH", $"{Environment.GetEnvironmentVariable("PATH")};{binPath}");
|
||||
AddDllDirectory(binPath);
|
||||
|
||||
Updater.Updater.CleanOld(Global.NetchDir);
|
||||
if (!Directory.Exists("bin") || !Directory.EnumerateFileSystemEntries("bin").Any())
|
||||
{
|
||||
i18N.Load("System");
|
||||
MessageBoxX.Show(i18N.Translate("Please extract all files then run the program!"));
|
||||
Environment.Exit(2);
|
||||
}
|
||||
|
||||
Updater.CleanOld(Global.NetchDir);
|
||||
|
||||
// 预创建目录
|
||||
var directories = new[] { "mode\\Custom", "data", "i18n", "logging" };
|
||||
@@ -47,7 +61,9 @@ namespace Netch
|
||||
Directory.CreateDirectory(item);
|
||||
|
||||
// 加载配置
|
||||
Configuration.Load();
|
||||
#pragma warning disable VSTHRD002
|
||||
Configuration.LoadAsync().Wait();
|
||||
#pragma warning restore VSTHRD002
|
||||
|
||||
if (!SingleInstance.IsFirstInstance)
|
||||
{
|
||||
@@ -57,7 +73,6 @@ namespace Netch
|
||||
}
|
||||
|
||||
SingleInstance.ArgumentsReceived.Subscribe(SingleInstance_ArgumentsReceived);
|
||||
SingleInstance.ListenForArgumentsFromSuccessiveInstances();
|
||||
|
||||
// 清理上一次的日志文件,防止淤积占用磁盘空间
|
||||
if (Directory.Exists("logging"))
|
||||
@@ -71,21 +86,21 @@ namespace Netch
|
||||
dir.Delete(true);
|
||||
}
|
||||
|
||||
InitConsole();
|
||||
|
||||
CreateLogger();
|
||||
|
||||
// 加载语言
|
||||
i18N.Load(Global.Settings.Language);
|
||||
|
||||
if (!Directory.Exists("bin") || !Directory.EnumerateFileSystemEntries("bin").Any())
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please extract all files then run the program!"));
|
||||
Environment.Exit(2);
|
||||
}
|
||||
|
||||
Global.Logger.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Task.Run(() => { Global.Logger.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); });
|
||||
Task.Run(LogEnvironment).Forget();
|
||||
CheckClr();
|
||||
CheckOS();
|
||||
|
||||
// 绑定错误捕获
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
Application.ThreadException += Application_OnException;
|
||||
Application.ApplicationExit += Application_OnExit;
|
||||
|
||||
Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
Application.EnableVisualStyles();
|
||||
@@ -93,16 +108,92 @@ namespace Netch
|
||||
Application.Run(Global.MainForm);
|
||||
}
|
||||
|
||||
private static void AttachAllocConsole()
|
||||
private static void LogEnvironment()
|
||||
{
|
||||
if (!AttachConsole(ATTACH_PARENT_PROCESS))
|
||||
AllocConsole();
|
||||
Log.Information("Netch Version: {Version}", $"{UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Log.Information("OS: {OSVersion}", Environment.OSVersion);
|
||||
Log.Information("SHA256: {Hash}", $"{Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}");
|
||||
Log.Information("System Language: {Language}", CultureInfo.CurrentCulture.Name);
|
||||
|
||||
if (Log.IsEnabled(LogEventLevel.Debug))
|
||||
{
|
||||
// TODO log level setting
|
||||
Task.Run(() => Log.Debug("Third-party Drivers:\n{Drivers}", string.Join(Constants.EOF, SystemInfo.SystemDrivers(false)))).Forget();
|
||||
Task.Run(() => Log.Debug("Running Processes: \n{Processes}", string.Join(Constants.EOF, SystemInfo.Processes(false)))).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Application_OnException(object sender, ThreadExceptionEventArgs e)
|
||||
private static void CheckClr()
|
||||
{
|
||||
Global.Logger.Error(e.Exception.ToString());
|
||||
Global.Logger.ShowLog();
|
||||
var framework = Assembly.GetExecutingAssembly().GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
|
||||
if (framework == null)
|
||||
{
|
||||
Log.Warning("TargetFrameworkAttribute null");
|
||||
return;
|
||||
}
|
||||
|
||||
var frameworkName = new FrameworkName(framework);
|
||||
|
||||
if (frameworkName.Version.Major != Environment.Version.Major)
|
||||
{
|
||||
Log.Information("CLR: {Version}", Environment.Version);
|
||||
Flags.NoSupport = true;
|
||||
if (!Global.Settings.NoSupportDialog)
|
||||
MessageBoxX.Show(
|
||||
i18N.TranslateFormat("{0} won't get developers' support, Please do not report any issues or seek help from developers.",
|
||||
"CLR " + Environment.Version),
|
||||
LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckOS()
|
||||
{
|
||||
if (Environment.OSVersion.Version.Build < 17763)
|
||||
{
|
||||
Flags.NoSupport = true;
|
||||
if (!Global.Settings.NoSupportDialog)
|
||||
MessageBoxX.Show(
|
||||
i18N.TranslateFormat("{0} won't get developers' support, Please do not report any issues or seek help from developers.",
|
||||
Environment.OSVersion),
|
||||
LogLevel.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitConsole()
|
||||
{
|
||||
PInvoke.AllocConsole();
|
||||
|
||||
ConsoleHwnd = PInvoke.GetConsoleWindow();
|
||||
#if RELEASE
|
||||
PInvoke.ShowWindow(ConsoleHwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void CreateLogger()
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
#if DEBUG
|
||||
.MinimumLevel.Verbose()
|
||||
#else
|
||||
.MinimumLevel.Debug()
|
||||
#endif
|
||||
.WriteTo.Async(c => c.File(Path.Combine(Global.NetchDir, Constants.LogFile),
|
||||
outputTemplate: Constants.OutputTemplate,
|
||||
rollOnFileSizeLimit: false))
|
||||
.WriteTo.Console(outputTemplate: Constants.OutputTemplate)
|
||||
.MinimumLevel.Override(@"Microsoft", LogEventLevel.Information)
|
||||
.Enrich.FromLogContext()
|
||||
.CreateLogger();
|
||||
}
|
||||
|
||||
private static void Application_OnException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
Log.Error(e.Exception, "Unhandled error");
|
||||
}
|
||||
|
||||
private static void Application_OnExit(object? sender, EventArgs eventArgs)
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
private static void SingleInstance_ArgumentsReceived(IEnumerable<string> args)
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<StartupObject>Netch.Netch</StartupObject>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<ApplicationIcon>Resources\Netch.ico</ApplicationIcon>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<NoWarn>VSTHRD100</NoWarn>
|
||||
<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>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
@@ -36,53 +30,57 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HMBSbige.SingleInstance" Version="5.0.0" />
|
||||
<PackageReference Include="HMBSbige.SingleInstance" Version="5.0.7" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.2.4089">
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.72" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="16.10.56" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.506-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.10.4539">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="4.1.2" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
|
||||
<PackageReference Include="Stun.Net" Version="5.0.0" />
|
||||
<PackageReference Include="System.Management" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0-rc.1.21451.13" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.9.1" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.8" />
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.8" />
|
||||
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
|
||||
<PackageReference Include="WindowsFirewallHelper" Version="2.1.4.81" />
|
||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Properties\Settings.Designer.cs">
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Forms\Mode\Route.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<None Remove="NativeMethods.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Condition="'$(PublishSingleFile)' == 'true'" AfterTargets="_ComputeFilesToBundle" Name="RemoveDupeAssemblies">
|
||||
<ItemGroup>
|
||||
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\build\native\x86\**" />
|
||||
<!-- .NET 6 SDK fixes MSB4018 "Multiple entries with the same BundleRelativePath",
|
||||
if still retain the following properties,
|
||||
you will encounter a "lib/netstandard2.0/Dial2Lib.dll not found" error
|
||||
-->
|
||||
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\Dia2Lib.dll" />
|
||||
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\OSExtensions.dll" />
|
||||
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\TraceReloggerLib.dll" />
|
||||
|
||||
26
Netch/Properties/Settings.Designer.cs
generated
26
Netch/Properties/Settings.Designer.cs
generated
@@ -1,26 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Netch.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
@@ -15,12 +15,12 @@
|
||||
"Stopping": "正在停止中",
|
||||
"Stopped": "已停止",
|
||||
"Starting {0}": "正在启动 {0}",
|
||||
"Starting NatTester": "正在启动 NAT 测试",
|
||||
"SetupBypass": "设置绕行规则",
|
||||
"Testing NAT Type": "正在测试 NAT 类型",
|
||||
"Setup Route Table Rule": "配置路由规则",
|
||||
"Test failed": "测试失败",
|
||||
"Starting update subscription": "正在更新订阅",
|
||||
"Subscription updated": "订阅更新完毕",
|
||||
"Register driver": "正在注册驱动",
|
||||
"Updating servers": "正在更新服务器",
|
||||
"Servers updated": "服务器更新完毕",
|
||||
"Installing netfilter2 driver": "正在安装 netfilter2 驱动",
|
||||
|
||||
"Server": "服务器",
|
||||
"Import Servers From Clipboard": "从剪贴板导入服务器",
|
||||
@@ -28,10 +28,10 @@
|
||||
"Netch is now minimized to the notification bar, double click this icon to restore.": "Netch 已最小化至通知栏,双击此图标恢复窗口",
|
||||
"New version available": "发现新版本",
|
||||
"Already latest version": "已经是最新版本",
|
||||
"New version found failed": "寻找新版本失败",
|
||||
"Check for update failed": "检查更新失败",
|
||||
"Mode": "模式",
|
||||
"Help": "帮助",
|
||||
"Check for updates": "检查更新",
|
||||
"Check for update": "检查更新",
|
||||
"Download and install now?": "立即下载并安装?",
|
||||
"Start downloading new version": "开始下载新版本",
|
||||
"Download update failed": "下载更新错误",
|
||||
@@ -48,9 +48,11 @@
|
||||
"Transfer Protocol": "传输协议",
|
||||
"Fake Type": "伪装类型",
|
||||
"Host": "主机",
|
||||
"Path": "路径",
|
||||
"Path": "路径/服务名称",
|
||||
"QUIC Security": "QUIC 加密方式",
|
||||
"QUIC Secret": "QUIC 加密密钥",
|
||||
"GRPC Mode": "QUIC 模式",
|
||||
"GRPC ServiceName": "QUIC 服务名称",
|
||||
"TLS Secure": "TLS 底层传输安全",
|
||||
"Use Mux": "Mux 多路复用",
|
||||
"Encrypt Method": "加密方式",
|
||||
@@ -62,16 +64,16 @@
|
||||
"Plugin": "插件",
|
||||
"Plugin Options": "插件参数",
|
||||
|
||||
"Subscribe": "订阅",
|
||||
"Manage Subscribe Links": "管理订阅链接",
|
||||
"Update Servers From Subscribe Links": "从订阅链接更新服务器",
|
||||
"Subscription": "订阅",
|
||||
"Manage Subscriptions": "管理订阅",
|
||||
"Update Servers": "更新服务器",
|
||||
"No subscription link": "没有任何一条订阅链接",
|
||||
"Updating {0}": "正在更新 {0}",
|
||||
"Update {1} server(s) from {0}": "从 {0} 更新 {1} 个服务器",
|
||||
"Update servers error from {0}": "从 {0} 更新服务器失败",
|
||||
"Update {1} server(s) from {0}": "从 {0} 更新了 {1} 个服务器",
|
||||
"Update servers failed from {0}": "从 {0} 更新服务器失败",
|
||||
"Confirm deletion?": "确认删除?",
|
||||
"DeleteServer": "删除订阅节点",
|
||||
"CopyLink": "复制链接",
|
||||
"Delete Servers": "删除订阅节点",
|
||||
"Copy link": "复制链接",
|
||||
"Status": "状态",
|
||||
"Link": "链接",
|
||||
"Unselect": "取消选择",
|
||||
@@ -87,6 +89,7 @@
|
||||
"Remove Netch Firewall Rules": "移除 Netch 防火墙规则",
|
||||
|
||||
"Open Directory": "打开目录",
|
||||
"Show/Hide Console": "显示/隐藏控制台",
|
||||
|
||||
"About": "关于",
|
||||
"FAQ": "常见问题",
|
||||
@@ -100,6 +103,7 @@
|
||||
"Please select a mode first": "请先选择一个模式",
|
||||
"Please enter a profile name first": "请先为该配置设置一个名称",
|
||||
"No saved profile here. Save a profile first by Ctrl+Click on the button": "当前按钮下没有保存配置,请先使用 CTRL + 左键 点击该按钮保存一个配置",
|
||||
"Lookup Server hostname failed": "解析服务器主机名失败",
|
||||
|
||||
"Used": "已使用",
|
||||
"Testing": "测试中",
|
||||
@@ -111,6 +115,9 @@
|
||||
"Scan": "扫描",
|
||||
"Save": "保存",
|
||||
"Modify": "修改",
|
||||
"Select": "选择",
|
||||
"Validation": "验证",
|
||||
"Action": "动作",
|
||||
"Select a folder": "选择一个目录",
|
||||
"Please enter an process name (xxx.exe)": "请输入一个进程名(xxx.exe)",
|
||||
"Rule does not conform to C++ regular expression syntax": "规则不符合 C++ 正则表达式语法",
|
||||
@@ -121,6 +128,7 @@
|
||||
"Please enter a mode remark": "请输入模式的备注",
|
||||
"File already exists.\n Please Change the filename": "文件名已存在,请修改文件名",
|
||||
"Please enter a mode filename": "请输入模式的文件名",
|
||||
"Above rules does not conform to C++ regular expression syntax": "以上规则不符合 C++ 正则表达式语法",
|
||||
|
||||
"Proxy Rule IPs": "代理规则 IP",
|
||||
"Bypass Rule IPs": "绕过规则 IP",
|
||||
@@ -129,6 +137,7 @@
|
||||
"Delete or not ? Will clean up the corresponding group of items in the server list": "是否删除?将会清理服务器列表中对应组的项目",
|
||||
"Remark can not be empty": "备注不可为空",
|
||||
"Link can not be empty": "链接不可为空",
|
||||
"Subscription with the specified remark already exists": "带有指定备注的订阅已存在",
|
||||
"Link must start with http:// or https://": "链接必须以 http:// 或 https:// 开头",
|
||||
|
||||
"Settings": "设置",
|
||||
@@ -147,18 +156,18 @@
|
||||
"Check update when opened": "打开软件时检查更新",
|
||||
"Check Beta update": "检查 Beta 更新",
|
||||
"Update Servers when opened": "打开软件时更新服务器",
|
||||
"Proxy Protocol": "代理协议",
|
||||
"Filter Protocol": "Filter 协议",
|
||||
"Handle process's DNS Hijack": "被代理进程 DNS 劫持",
|
||||
"Global ICMP Hijack": "全局 ICMP 劫持",
|
||||
"Child Process Handle": "子进程代理",
|
||||
"ProfileCount": "快捷配置数量",
|
||||
"Delay test after start": "启动后延迟测试",
|
||||
"ServerPingType": "测速方式",
|
||||
"ICMP Delay(ms)": "ICMP 延迟(毫秒)",
|
||||
"Profile Count": "快捷配置数量",
|
||||
"Delay test after start(sec)": "启动后延迟测试(秒)",
|
||||
"Ping Protocol": "延迟测试协议",
|
||||
"Detection Tick(sec)": "检测心跳(秒)",
|
||||
"STUN Server": "STUN 服务器",
|
||||
"Language": "语言",
|
||||
"Resolve Server Hostname": "解析服务器主机名",
|
||||
"FullCone Support (Required Server Xray-core v1.3.0+)": "FullCone 支持(需服务端 Xray-core v1.3.0+)",
|
||||
"Disable Support Warning": "停用支持警告",
|
||||
|
||||
"Profile": "配置名",
|
||||
"Profiles": "配置",
|
||||
@@ -168,5 +177,8 @@
|
||||
"Exit": "退出",
|
||||
|
||||
"The {0} port is in use.": "{0} 端口已被占用",
|
||||
"The {0} port is reserved by system.": "{0} 端口是系统保留端口"
|
||||
"The {0} port is reserved by system.": "{0} 端口是系统保留端口",
|
||||
|
||||
"{0} won't get developers' support, Please do not report any issues or seek help from developers.": "{0} 将不会得到开发者的支持,请不要报告任何问题或寻求开发人员的帮助。",
|
||||
"No Support": "不受支持"
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
public class SSController : Guard, IServerController
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
|
||||
|
||||
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" };
|
||||
|
||||
public override string Name { get; } = "Shadowsocks";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (Shadowsocks)s;
|
||||
|
||||
var command = new SSParameter
|
||||
{
|
||||
s = server.AutoResolveHostname(),
|
||||
p = server.Port,
|
||||
b = this.LocalAddress(),
|
||||
l = this.Socks5LocalPort(),
|
||||
m = server.EncryptMethod,
|
||||
k = server.Password,
|
||||
u = true,
|
||||
plugin = server.Plugin,
|
||||
plugin_opts = server.PluginOption
|
||||
};
|
||||
|
||||
StartInstanceAuto(command.ToString());
|
||||
}
|
||||
|
||||
[Verb]
|
||||
private class SSParameter : ParameterBase
|
||||
{
|
||||
public string? s { get; set; }
|
||||
|
||||
public ushort? p { get; set; }
|
||||
|
||||
public string? b { get; set; }
|
||||
|
||||
public ushort? l { get; set; }
|
||||
|
||||
public string? m { get; set; }
|
||||
|
||||
public string? k { get; set; }
|
||||
|
||||
public bool u { get; set; }
|
||||
|
||||
[Full]
|
||||
[Optional]
|
||||
public string? plugin { get; set; }
|
||||
|
||||
[Full]
|
||||
[Optional]
|
||||
[RealName("plugin-opts")]
|
||||
public string? plugin_opts { get; set; }
|
||||
|
||||
[Full]
|
||||
[Quote]
|
||||
[Optional]
|
||||
public string? acl { get; set; }
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Netch/Servers/Shadowsocks/ShadowsocksController.cs
Normal file
47
Netch/Servers/Shadowsocks/ShadowsocksController.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class ShadowsocksController : Guard, IServerController
|
||||
{
|
||||
public ShadowsocksController() : base("Shadowsocks.exe")
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords => new[] { "listening at" };
|
||||
|
||||
protected override IEnumerable<string> FailedKeywords => new[] { "Invalid config path", "usage", "plugin service exit unexpectedly" };
|
||||
|
||||
public override string Name => "Shadowsocks";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public async Task<Socks5LocalServer> StartAsync(Server s)
|
||||
{
|
||||
var server = (ShadowsocksServer)s;
|
||||
|
||||
var arguments = new object?[]
|
||||
{
|
||||
"-s", await server.AutoResolveHostnameAsync(),
|
||||
"-p", server.Port,
|
||||
"-b", this.LocalAddress(),
|
||||
"-l", this.Socks5LocalPort(),
|
||||
"-m", server.EncryptMethod,
|
||||
"-k", server.Password,
|
||||
"-u", SpecialArgument.Flag,
|
||||
"--plugin", server.Plugin,
|
||||
"--plugin-opts", server.PluginOption
|
||||
};
|
||||
|
||||
await StartGuardAsync(Arguments.Format(arguments));
|
||||
return new Socks5LocalServer(IPAddress.Loopback.ToString(), this.Socks5LocalPort(), server.Hostname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks.Form
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class ShadowsocksForm : ServerForm
|
||||
{
|
||||
public ShadowsocksForm(Shadowsocks? server = default)
|
||||
public ShadowsocksForm(ShadowsocksServer? server = default)
|
||||
{
|
||||
server ??= new Shadowsocks();
|
||||
server ??= new ShadowsocksServer();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password", s => !s.IsNullOrWhiteSpace(), s => server.Password = s, server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", SSGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
@@ -1,11 +1,15 @@
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class Shadowsocks : Server
|
||||
public class ShadowsocksServer : Server
|
||||
{
|
||||
public override string Type { get; } = "SS";
|
||||
public override string MaskedData()
|
||||
{
|
||||
return $"{EncryptMethod} + {Plugin}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
@@ -1,18 +1,17 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks.Form;
|
||||
using Netch.Servers.Shadowsocks.Models.SSD;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class SSUtil : IServerUtil
|
||||
public class ShadowsocksUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 1;
|
||||
|
||||
@@ -24,11 +23,11 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public string[] UriScheme { get; } = { "ss", "ssd" };
|
||||
|
||||
public Type ServerType { get; } = typeof(Shadowsocks);
|
||||
public Type ServerType { get; } = typeof(ShadowsocksServer);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksForm((Shadowsocks)s).ShowDialog();
|
||||
new ShadowsocksForm((ShadowsocksServer)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -38,7 +37,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (Shadowsocks)s;
|
||||
var server = (ShadowsocksServer)s;
|
||||
// ss://method:password@server:port#Remark
|
||||
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" +
|
||||
HttpUtility.UrlEncode(server.Remark);
|
||||
@@ -46,7 +45,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public IServerController GetController()
|
||||
{
|
||||
return new SSController();
|
||||
return new ShadowsocksController();
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
@@ -62,13 +61,11 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (Shadowsocks)s;
|
||||
var server = (ShadowsocksServer)s;
|
||||
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Global.Logger.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Log.Warning("Unsupported SS Encrypt Method: {Method}", server.EncryptMethod);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -76,26 +73,26 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public IEnumerable<Server> ParseSsdUri(string s)
|
||||
{
|
||||
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
|
||||
var json = JsonSerializer.Deserialize<SSDJObject>(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)
|
||||
return json.servers.Select(server => new ShadowsocksServer
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public Shadowsocks ParseSsUri(string text)
|
||||
public ShadowsocksServer ParseSsUri(string text)
|
||||
{
|
||||
var data = new Shadowsocks();
|
||||
var data = new ShadowsocksServer();
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
if (text.Contains("#"))
|
||||
@@ -1,9 +1,9 @@
|
||||
#nullable disable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class Main
|
||||
public class SSDJObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 机场名
|
||||
@@ -38,6 +38,6 @@ namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
/// <summary>
|
||||
/// 服务器数组
|
||||
/// </summary>
|
||||
public List<SSDServer> servers;
|
||||
public List<SSDServerJObject> servers;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class SSDServer
|
||||
public class SSDServerJObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
@@ -1,6 +1,10 @@
|
||||
#nullable disable
|
||||
namespace Netch.Servers.Shadowsocks.Models
|
||||
namespace Netch.Servers
|
||||
{
|
||||
/// <summary>
|
||||
/// Import Shadowsocks Server from Json Configuration
|
||||
/// <see cref="Utils.ShareLink.ParseText"/>
|
||||
/// </summary>
|
||||
public class ShadowsocksConfig
|
||||
{
|
||||
public string server { get; set; }
|
||||
@@ -1,87 +0,0 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
public class SSRController : Guard, IServerController
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "ShadowsocksR.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "listening at" };
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "Invalid config path", "usage" };
|
||||
|
||||
public override string Name { get; } = "ShadowsocksR";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (ShadowsocksR)s;
|
||||
|
||||
var command = new SSRParameter
|
||||
{
|
||||
s = server.AutoResolveHostname(),
|
||||
p = server.Port,
|
||||
k = server.Password,
|
||||
m = server.EncryptMethod,
|
||||
t = "120",
|
||||
O = server.Protocol,
|
||||
G = server.ProtocolParam,
|
||||
o = server.OBFS,
|
||||
g = server.OBFSParam,
|
||||
b = this.LocalAddress(),
|
||||
l = this.Socks5LocalPort(),
|
||||
u = true
|
||||
};
|
||||
|
||||
StartInstanceAuto(command.ToString());
|
||||
}
|
||||
|
||||
[Verb]
|
||||
class SSRParameter : ParameterBase
|
||||
{
|
||||
public string? s { get; set; }
|
||||
|
||||
public ushort? p { get; set; }
|
||||
|
||||
[Quote]
|
||||
public string? k { get; set; }
|
||||
|
||||
public string? m { get; set; }
|
||||
|
||||
public string? t { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? O { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? G { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? o { get; set; }
|
||||
|
||||
[Optional]
|
||||
public string? g { get; set; }
|
||||
|
||||
public string? b { get; set; }
|
||||
|
||||
public ushort? l { get; set; }
|
||||
|
||||
public bool u { get; set; }
|
||||
|
||||
[Full]
|
||||
[Quote]
|
||||
[Optional]
|
||||
public string? acl { get; set; }
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Netch/Servers/ShadowsocksR/ShadowsocksRController.cs
Normal file
50
Netch/Servers/ShadowsocksR/ShadowsocksRController.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Controllers;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class ShadowsocksRController : Guard, IServerController
|
||||
{
|
||||
public ShadowsocksRController() : base("ShadowsocksR.exe")
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords => new[] { "listening at" };
|
||||
|
||||
protected override IEnumerable<string> FailedKeywords => new[] { "Invalid config path", "usage" };
|
||||
|
||||
public override string Name => "ShadowsocksR";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string? LocalAddress { get; set; }
|
||||
|
||||
public async Task<Socks5LocalServer> StartAsync(Server s)
|
||||
{
|
||||
var server = (ShadowsocksRServer)s;
|
||||
|
||||
var arguments = new object?[]
|
||||
{
|
||||
"-s", await server.AutoResolveHostnameAsync(),
|
||||
"-p", server.Port,
|
||||
"-k", server.Password,
|
||||
"-m", server.EncryptMethod,
|
||||
"-t", 120,
|
||||
"-O", server.Protocol,
|
||||
"-G", server.ProtocolParam,
|
||||
"-o", server.OBFS,
|
||||
"-g", server.OBFSParam,
|
||||
"-b", this.LocalAddress(),
|
||||
"-l", this.Socks5LocalPort(),
|
||||
"-u", SpecialArgument.Flag
|
||||
};
|
||||
|
||||
await StartGuardAsync(Arguments.Format(arguments));
|
||||
return new Socks5LocalServer(IPAddress.Loopback.ToString(), this.Socks5LocalPort(), server.Hostname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using Netch.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR.Form
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class ShadowsocksRForm : ServerForm
|
||||
{
|
||||
public ShadowsocksRForm(ShadowsocksR? server = default)
|
||||
public ShadowsocksRForm(ShadowsocksRServer? server = default)
|
||||
{
|
||||
server ??= new ShadowsocksR();
|
||||
server ??= new ShadowsocksRServer();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password", s => !s.IsNullOrWhiteSpace(), s => server.Password = s, server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", SSRGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
@@ -1,11 +1,15 @@
|
||||
using Netch.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class ShadowsocksR : Server
|
||||
public class ShadowsocksRServer : Server
|
||||
{
|
||||
public override string Type { get; } = "SSR";
|
||||
public override string MaskedData()
|
||||
{
|
||||
return $"{EncryptMethod} + {Protocol} + {OBFS}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
@@ -1,15 +1,14 @@
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.ShadowsocksR.Form;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Serilog;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
namespace Netch.Servers
|
||||
{
|
||||
public class SSRUtil : IServerUtil
|
||||
public class ShadowsocksRUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 1;
|
||||
|
||||
@@ -21,11 +20,11 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public string[] UriScheme { get; } = { "ssr" };
|
||||
|
||||
public Type ServerType { get; } = typeof(ShadowsocksR);
|
||||
public Type ServerType { get; } = typeof(ShadowsocksRServer);
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksRForm((ShadowsocksR)s).ShowDialog();
|
||||
new ShadowsocksRForm((ShadowsocksRServer)s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
@@ -35,7 +34,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR)s;
|
||||
var server = (ShadowsocksRServer)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)
|
||||
@@ -49,7 +48,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public IServerController GetController()
|
||||
{
|
||||
return new SSRController();
|
||||
return new ShadowsocksRController();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,7 +111,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
if (SSGlobal.EncryptMethods.Contains(method) && protocol == "origin" && obfs == "plain")
|
||||
return new[]
|
||||
{
|
||||
new Shadowsocks.Shadowsocks
|
||||
new ShadowsocksServer
|
||||
{
|
||||
Hostname = serverAddr,
|
||||
Port = serverPort,
|
||||
@@ -125,7 +124,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
return new[]
|
||||
{
|
||||
new ShadowsocksR
|
||||
new ShadowsocksRServer
|
||||
{
|
||||
Hostname = serverAddr,
|
||||
Port = serverPort,
|
||||
@@ -143,22 +142,22 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR)s;
|
||||
var server = (ShadowsocksRServer)s;
|
||||
if (!SSRGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Global.Logger.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}");
|
||||
Log.Error("Unsupported ShadowsocksR Encrypt method: {Method}", server.EncryptMethod);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSRGlobal.Protocols.Contains(server.Protocol))
|
||||
{
|
||||
Global.Logger.Error($"不支持的 SSR 协议:{server.Protocol}");
|
||||
Log.Error("Unsupported ShadowsocksR Protocol: {Protocol}", server.Protocol);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSRGlobal.OBFSs.Contains(server.OBFS))
|
||||
{
|
||||
Global.Logger.Error($"不支持的 SSR 混淆:{server.OBFS}");
|
||||
Log.Error("Unsupported ShadowsocksR Obfs: {Obfs}", server.OBFS);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using Netch.Models;
|
||||
using Netch.Servers.V2ray;
|
||||
|
||||
namespace Netch.Servers.Socks5
|
||||
{
|
||||
public class S5Controller : V2rayController
|
||||
{
|
||||
public override string Name { get; } = "Socks5";
|
||||
|
||||
public override void Start(in Server s, in Mode mode)
|
||||
{
|
||||
var server = (Socks5)s;
|
||||
if (server.Auth())
|
||||
base.Start(s, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Servers.Socks5
|
||||
{
|
||||
public class Socks5 : Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string? Password;
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
public string? Username;
|
||||
|
||||
public override string Type { get; } = "Socks5";
|
||||
|
||||
public bool Auth()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user