Compare commits

...

70 Commits

Author SHA1 Message Date
ChsBuffer
764d42efe2 Bump version to 1.8.4 2021-05-11 22:03:11 +08:00
ChsBuffer
8b81df03c4 Update TUNController.cs 2021-05-11 22:02:45 +08:00
ChsBuffer
4cc5998440 Fix suffixed version newer than release version 2021-05-11 17:17:51 +08:00
ChsBuffer
2051dd1bfe Update Nuget Packages 2021-05-10 10:08:45 +08:00
ChsBuffer
b167674d37 Update NetRoute.FillTemplate 2021-05-10 10:07:34 +08:00
ChsBuffer
74caeeaf42 Refactor TUNController 2021-05-09 15:31:43 +08:00
ChsBuffer
60dd3c8965 Refactor: Rearrange MainForm 2021-05-07 15:34:37 +08:00
ChsBuffer
ee2d35cb5d Refactor: ModeHelper, Mode.Type, Netch.Enums.ModeType 2021-05-06 23:43:13 +08:00
ChsBuffer
6f6ff85549 Refactor Guard Thread safety 2021-05-04 10:23:53 +08:00
ChsBuffer
9a8c4d6093 Fix: CloseLogFile() Thread safety 2021-05-04 10:17:33 +08:00
ChsBuffer
00268d67fa TUNController: check Interop Init() return value.
when false, throws MessageException
2021-05-04 00:24:09 +08:00
Connection Refused
b1f89c177d Update README.md 2021-05-01 11:53:07 +08:00
ChsBuffer
4a543dcf1a Refactor: Extract GetNetworkInterface By InterfaceIndex
close #630
2021-04-30 18:45:51 +08:00
ChsBuffer
5b5262e03e Update code style 2021-04-30 17:20:29 +08:00
ChsBuffer
60f0637b03 Refactor: MainForm AddServerMenuStrip get IServerUtil from Tag 2021-04-30 17:02:34 +08:00
ChsBuffer
460d295a66 Refactor TryReleaseTcpPort Process.MainModule.FileName null handling 2021-04-30 17:01:11 +08:00
ChsBuffer
ccd46144ab Refactor: save configuration 2021-04-30 15:48:43 +08:00
ChsBuffer
84e481f704 fix typo 2021-04-30 15:45:12 +08:00
ChsBuffer
fb64951003 Refactor: name, namespace 2021-04-30 15:24:37 +08:00
Connection Refused
258880ef95 Update README.md 2021-04-27 08:56:05 +08:00
Connection Refused
2bda0bdf8e Update issue templates 2021-04-27 08:47:18 +08:00
Connection Refused
bc0e5d0dcf Rename scripts 2021-04-27 08:43:35 +08:00
Connection Refused
4e4af89fbe Remove README.zh-CN.md 2021-04-27 08:43:31 +08:00
Connection Refused
1e9ff83aa2 Update README.md 2021-04-27 08:40:22 +08:00
Connection Refused
a4d8619944 Update README.md 2021-04-27 08:38:39 +08:00
Connection Refused
0bb54abe6c Update README.md 2021-04-27 08:03:51 +08:00
Connection Refused
0ad18ee566 Update README.md 2021-04-27 08:03:26 +08:00
Connection Refused
80460c0a21 Update README.md 2021-04-27 08:02:14 +08:00
Connection Refused
098680482e Merge pull request #628 from NetchX/dependabot/nuget/Microsoft.Diagnostics.Tracing.TraceEvent-2.0.68
Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.67 to 2.0.68
2021-04-27 07:24:17 +08:00
dependabot[bot]
16d7f53ee3 Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.67 to 2.0.68
Bumps [Microsoft.Diagnostics.Tracing.TraceEvent](https://github.com/Microsoft/perfview) from 2.0.67 to 2.0.68.
- [Release notes](https://github.com/Microsoft/perfview/releases)
- [Commits](https://github.com/Microsoft/perfview/compare/P2.0.67...P2.0.68)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-26 23:06:25 +00:00
Connection Refused
ed946c44a2 Merge pull request #627 from NetchX/dependabot/nuget/Microsoft.Diagnostics.Tracing.TraceEvent-2.0.67
Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.66 to 2.0.67
2021-04-24 01:38:08 +08:00
dependabot[bot]
62c28ccab2 Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.66 to 2.0.67
Bumps [Microsoft.Diagnostics.Tracing.TraceEvent](https://github.com/Microsoft/perfview) from 2.0.66 to 2.0.67.
- [Release notes](https://github.com/Microsoft/perfview/releases)
- [Commits](https://github.com/Microsoft/perfview/compare/P2.0.66...P2.0.67)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-22 23:12:13 +00:00
ChsBuffer
a2326389db Fix: Use WMI to set dummy Dns on the tun interface to ensure DNS is hijacked 2021-04-21 18:25:37 +08:00
Connection Refused
b0086cc854 Add ethereum donate address 2021-04-21 17:33:25 +08:00
Connection Refused
d2548d2893 Add ethereum donate address 2021-04-21 17:32:50 +08:00
Connection Refused
101d8c5a25 Update telegram links 2021-04-21 17:27:33 +08:00
Bruce Wayne
1b36b707f6 Update issue forms 2021-04-21 11:20:03 +08:00
Bruce Wayne
a94bf0d53d Update issue forms 2021-04-21 11:17:24 +08:00
Bruce Wayne
32a9261041 Update issue forms 2021-04-21 09:43:29 +08:00
Bruce Wayne
2b0530d9b0 Update issue forms 2021-04-21 09:23:52 +08:00
Bruce Wayne
2d85e78b77 Drop old issue template 2021-04-21 09:22:12 +08:00
Connection Refused
b8b4dbfb0a Update release.yml 2021-04-18 15:53:29 +08:00
Connection Refused
025eda8286 Update README.md 2021-04-18 15:53:05 +08:00
Connection Refused
44da2e8011 Bump version to 1.8.3 2021-04-09 09:22:27 +08:00
Connection Refused
54daff70b3 Update build.ps1 2021-04-09 09:21:17 +08:00
Connection Refused
b218e785d8 Update build.ps1 2021-04-09 09:21:05 +08:00
Connection Refused
5b857cc518 Merge pull request #610 from NetchX/dependabot/nuget/Vanara.PInvoke.User32-3.3.8
Bump Vanara.PInvoke.User32 from 3.3.7 to 3.3.8
2021-04-08 22:59:04 +08:00
Connection Refused
4693025576 Merge pull request #609 from NetchX/dependabot/nuget/Vanara.PInvoke.IpHlpApi-3.3.8
Bump Vanara.PInvoke.IpHlpApi from 3.3.7 to 3.3.8
2021-04-08 22:58:55 +08:00
dependabot[bot]
46eefd3db9 Bump Vanara.PInvoke.User32 from 3.3.7 to 3.3.8
Bumps [Vanara.PInvoke.User32](https://github.com/dahall/vanara) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/dahall/vanara/releases)
- [Commits](https://github.com/dahall/vanara/compare/v3.3.7...v3.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-07 23:04:23 +00:00
dependabot[bot]
eb1ee9e820 Bump Vanara.PInvoke.IpHlpApi from 3.3.7 to 3.3.8
Bumps [Vanara.PInvoke.IpHlpApi](https://github.com/dahall/vanara) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/dahall/vanara/releases)
- [Commits](https://github.com/dahall/vanara/compare/v3.3.7...v3.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-07 23:04:15 +00:00
Connection Refused
b501ed38c4 Enable SelfContained 2021-04-05 02:16:48 +08:00
Connection Refused
6f1b0ee21f Merge remote-tracking branch 'refs/remotes/origin/master' 2021-04-05 02:11:19 +08:00
Connection Refused
ce6d96a779 Bump version to 1.8.3-Beta1145141919 2021-04-05 02:11:08 +08:00
Connection Refused
39f0f87b3a Update Netch.csproj 2021-04-05 02:09:39 +08:00
Connection Refused
642c4d1af8 Fix download.ps1 2021-04-05 02:04:50 +08:00
Connection Refused
d42aa8f184 Update build.ps1 2021-04-05 02:03:02 +08:00
Connection Refused
9c02ef353f Revert 2021-04-05 01:49:13 +08:00
ChsBuffer
1b4e7d41cc Update Netch.csproj: PostBuild 2021-04-04 21:59:43 +08:00
ChsBuffer
3d7dcbbffe Fix open links in about error 2021-04-04 21:59:41 +08:00
ChsBuffer
be9d7d6845 Update build script: exit when curl failed 2021-04-04 21:57:31 +08:00
ChsBuffer
a3620ed162 Normalize all the line endings 2021-04-02 13:58:45 +08:00
ChsBuffer
ba8c60675e Update download.ps1 2021-04-02 13:27:17 +08:00
ChsBuffer
c9a1265231 Update download.ps1 2021-04-02 13:06:21 +08:00
Connection Refused
92b030ebd9 Update release.yml 2021-04-02 08:53:30 +08:00
Connection Refused
7fd24d46d3 Update build.yml 2021-04-02 08:53:17 +08:00
Connection Refused
e2f6a58fde Update download.ps1 2021-04-02 08:50:22 +08:00
ChsBuffer
5f31109bcf Update SuffixVersion 2021-04-02 03:59:49 +08:00
Connection Refused
354608a72c Update README.md 2021-04-02 02:59:29 +08:00
Connection Refused
5803b94ae9 Update NativeMethods 2021-04-02 02:40:13 +08:00
Connection Refused
ee7c6aa608 Update .gitignore 2021-04-02 02:33:46 +08:00
102 changed files with 1131 additions and 1271 deletions

View File

@@ -12,6 +12,7 @@ tab_width = 4
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers = false
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
csharp_space_after_cast = false
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
@@ -27,7 +28,7 @@ dotnet_style_qualification_for_property = false:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
# ReSharper properties
resharper_align_multiline_switch_expression = true
resharper_align_multiline_switch_expression = false
resharper_align_multline_type_parameter_constrains = true
resharper_blank_lines_after_block_statements = 0
resharper_blank_lines_after_multiline_statements = 1
@@ -73,7 +74,7 @@ resharper_place_simple_initializer_on_single_line = true
resharper_place_simple_switch_expression_on_single_line = true
resharper_show_autodetect_configure_formatting_tip = false
resharper_space_around_arrow_op = true
resharper_space_within_single_line_array_initializer_braces = false
resharper_space_within_single_line_array_initializer_braces = true
resharper_use_indent_from_vs = false
resharper_wrap_array_initializer_style = wrap_if_long
resharper_wrap_before_arrow_with_expressions = true

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.cs text

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,29 +0,0 @@
---
name: '错误报告'
about: '创建错误报告以帮助我们改进'
title: ''
labels: '需要核实'
assignees: ''
---
**确保你已经看过 readme也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
**错误描述**
对错误的清晰简洁描述
**复现步骤**
1. 打开 Netch 软件
2. ...
**日志**
强烈建议附上任何在 `Netch\logging` 文件夹下面的日志。
**错误截图**
如果适用,请添加屏幕截图以帮助解释您的问题
**信息**
- 操作系统:[例如 Windows 10 专业版 64 位 1903]
- 软件版本:[例如 1.0.0-STABLE 64 位]
**额外信息**

View File

@@ -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 相关的截图、文件

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -1,15 +0,0 @@
---
name: '功能请求'
about: '建议这个项目的想法'
title: ''
labels: 'Status: Review Needed'
assignees: ''
---
**确保你已经看过 readme也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
**功能描述**
简明扼要地描述需要的功能
**额外信息**

View File

@@ -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

View File

@@ -1,4 +1,4 @@
name: Netch CI
name: Netch Build CI
on: [push, pull_request]
jobs:

View File

@@ -1,4 +1,4 @@
name: Netch CI
name: Netch Release CI
on:
push:
tags:
@@ -40,7 +40,7 @@ jobs:
files: |
Netch.7z
body: |
[![](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/Netch) [![](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/Netch_Discuss_Group)
[![](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/netch_channel) [![](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/netch_group)
## 更新日志
* 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新

10
.gitignore vendored
View File

@@ -1,5 +1,5 @@
.vs/
.idea/
*/bin/
*/obj/
*.csproj.user
/.vs
/.vscode
/.idea
/release
/DataCache

View File

@@ -1,25 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.ActiveCfg = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.Build.0 = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.ActiveCfg = Release|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6EC9B043-ACA5-4BB9-96DB-493A2EF6E43F}
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.ActiveCfg = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.Build.0 = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.ActiveCfg = Release|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6EC9B043-ACA5-4BB9-96DB-493A2EF6E43F}
EndGlobalSection
EndGlobal

3
Netch/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/bin
/obj
/*.csproj.user

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using static Netch.Interops.AioDNSInterops;
using Netch.Interfaces;
using static Netch.Interops.AioDNS;
namespace Netch.Controllers
{

View File

@@ -1,3 +1,5 @@
using Netch.Models;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -7,15 +9,13 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Netch.Models;
using Netch.Utils;
using Timer = System.Timers.Timer;
namespace Netch.Controllers
{
public abstract class Guard
{
private readonly Timer _flushFileStreamTimer = new(300) {AutoReset = true};
private readonly Timer _flushFileStreamTimer = new(300) { AutoReset = true };
private FileStream? _logFileStream;
@@ -199,15 +199,22 @@ namespace Netch.Controllers
_logStreamWriter!.WriteLine(line);
}
private readonly object LogStreamLock = new();
private void CloseLogFile()
{
if (!RedirectToFile)
return;
_flushFileStreamTimer.Enabled = false;
_logStreamWriter?.Close();
_logFileStream?.Close();
_logStreamWriter = _logStreamWriter = null;
lock (LogStreamLock)
{
if (_logFileStream == null)
return;
_flushFileStreamTimer.Enabled = false;
_logStreamWriter?.Close();
_logFileStream?.Close();
_logStreamWriter = _logStreamWriter = null;
}
}
#endregion

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
@@ -54,17 +55,17 @@ namespace Netch.Controllers
public static void Start(Server server, Mode mode)
{
Global.Logger.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
Global.Logger.Info($"启动主控制器: {server.Type} [{(int)mode.Type}]{mode.Remark}");
Server = server;
Mode = mode;
// 刷新DNS缓存
NativeMethods.FlushDNSResolverCache();
// 刷新 DNS 缓存
NativeMethods.RefreshDNSCache();
if (DnsUtils.Lookup(server.Hostname) == null)
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
// 添加Netch到防火墙
// 添加 Netch 到防火墙
Firewall.AddNetchFwRules();
try
@@ -122,7 +123,7 @@ namespace Netch.Controllers
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName);
if (port != null)
TryReleaseTcpPort((ushort) port, portName);
TryReleaseTcpPort((ushort)port, portName);
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
@@ -186,16 +187,9 @@ namespace Netch.Controllers
{
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
{
string fileName;
try
{
fileName = p.MainModule?.FileName ?? throw new Exception(); // TODO what's this exception?
}
catch (Exception e)
{
Global.Logger.Warning(e.ToString());
var fileName = p.MainModule?.FileName;
if (fileName == null)
continue;
}
if (fileName.StartsWith(Global.NetchDir))
{

View File

@@ -3,12 +3,13 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using Netch.Interfaces;
using Netch.Interops;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
using Netch.Utils;
using static Netch.Interops.RedirectorInterop;
using static Netch.Interops.Redirector;
namespace Netch.Controllers
{
@@ -148,7 +149,7 @@ namespace Netch.Controllers
{
Dial(NameList.TYPE_CLRNAME, "");
var invalidList = new List<string>();
foreach (var s in mode.FullRule)
foreach (var s in mode.GetRules())
{
if (s.StartsWith("!"))
{

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Netch.Interfaces;
using Netch.Utils;
namespace Netch.Controllers

View File

@@ -6,8 +6,10 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Netch.Forms;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
namespace Netch.Controllers
{
@@ -17,9 +19,7 @@ namespace Netch.Controllers
public override string MainFile { get; protected set; } = "pcap2socks.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"└"};
private readonly OutboundAdapter _outbound = new();
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "└" };
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
@@ -32,13 +32,15 @@ namespace Netch.Controllers
_form = new LogForm(Global.MainForm);
_form.CreateControl();
var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}");
var outboundNetworkInterface = NetworkInterfaceUtils.GetBest();
var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.Id}");
if (server is Socks5 socks5 && !socks5.Auth())
argument.Append($" --destination {server.AutoResolveHostname()}:{server.Port}");
else
argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}");
argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}");
argument.Append($" {mode.GetRules().FirstOrDefault() ?? "-P n"}");
StartInstanceAuto(argument.ToString());
}

View File

@@ -1,42 +1,46 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Netch.Enums;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
using Vanara.PInvoke;
using static Netch.Interops.TUNInterop;
using static Vanara.PInvoke.Ws2_32;
using Netch.Interops;
using static Netch.Interops.tun2socks;
namespace Netch.Controllers
{
public class TUNController : IModeController
{
private readonly List<string> _directIPs = new();
public string Name => "tun2socks";
private readonly List<string> _proxyIPs = new();
private const string DummyDns = "6.6.6.6";
public readonly DNSController DNSController = new();
private readonly DNSController _aioDnsController = new();
public string Name { get; } = "tun2socks";
private NetRoute _outbound;
private NetRoute _tun;
private readonly OutboundAdapter _outboundAdapter = new();
private IAdapter _tunAdapter = null!;
private IPAddress _serverAddresses = null!;
private Mode _mode = null!;
public void Start(in Mode mode)
{
_mode = mode;
var server = MainController.Server!;
_serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start
IPAddress address;
(_outbound, address) = NetRoute.GetBestRouteTemplate();
CheckDriver();
Dial(NameList.TYPE_ADAPMTU, "1500");
Dial(NameList.TYPE_BYPBIND, _outboundAdapter.Address.ToString());
Dial(NameList.TYPE_BYPBIND, address.ToString());
Dial(NameList.TYPE_BYPLIST, "disabled");
#region Server
@@ -80,32 +84,111 @@ namespace Netch.Controllers
else
{
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
DNSController.Start();
_aioDnsController.Start();
Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}");
}
#endregion
Global.Logger.Debug("tun2socks init");
Init();
if (!Init())
throw new MessageException("tun2socks start failed, reboot your system and start again.");
_tunAdapter = new TunAdapter();
var tunIndex = (int)RouteHelper.ConvertLuidToIndex(tun_luid());
_tun = NetRoute.TemplateBuilder(Global.Settings.TUNTAP.Gateway, tunIndex);
NativeMethods.CreateUnicastIP((int) AddressFamily.InterNetwork,
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
Global.Settings.TUNTAP.Address,
Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
_tunAdapter.InterfaceIndex);
(byte)Utils.Utils.SubnetToCidr(Global.Settings.TUNTAP.Netmask),
(ulong)tunIndex);
SetupRouteTable(mode);
}
private readonly string BinDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll");
private readonly string SysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
#region Route
private void SetupRouteTable(Mode mode)
{
Global.MainForm.StatusText(i18N.Translate("Setup Route Table Rule"));
Global.Logger.Info("设置路由规则");
// Server Address
if (!IPAddress.IsLoopback(_serverAddresses))
RouteUtils.CreateRoute(_outbound.FillTemplate(_serverAddresses.ToString(), 32));
// Global Bypass IPs
RouteUtils.CreateRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs);
var tunNetworkInterface = NetworkInterfaceUtils.Get(_tun.InterfaceIndex);
switch (mode.Type)
{
case ModeType.ProxyRuleIPs:
// rules
RouteUtils.CreateRouteFill(_tun, mode.GetRules());
if (Global.Settings.TUNTAP.ProxyDNS)
{
tunNetworkInterface.SetDns(DummyDns);
// proxy dummy dns
RouteUtils.CreateRoute(_tun.FillTemplate(DummyDns, 32));
if (!Global.Settings.TUNTAP.UseCustomDNS)
// proxy AioDNS other dns
RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.OtherDNS), 32));
}
break;
case ModeType.BypassRuleIPs:
RouteUtils.CreateRouteFill(_outbound, mode.GetRules());
tunNetworkInterface.SetDns(DummyDns);
if (!Global.Settings.TUNTAP.UseCustomDNS)
// bypass AioDNS other dns
RouteUtils.CreateRoute(_tun.FillTemplate(Utils.Utils.GetHostFromUri(Global.Settings.AioDNS.ChinaDNS), 32));
NetworkInterfaceUtils.SetInterfaceMetric(_tun.InterfaceIndex, 0);
RouteUtils.CreateRoute(_tun.FillTemplate("0.0.0.0", 0));
break;
}
}
private void ClearRouteTable()
{
if (!IPAddress.IsLoopback(_serverAddresses))
RouteUtils.DeleteRoute(_outbound.FillTemplate(_serverAddresses.ToString(), 32));
RouteUtils.DeleteRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs);
switch (_mode.Type)
{
case ModeType.BypassRuleIPs:
RouteUtils.DeleteRouteFill(_outbound, _mode.GetRules());
NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex);
break;
}
}
#endregion
public void Stop()
{
var tasks = new[]
{
Task.Run(Free),
Task.Run(ClearRouteTable),
Task.Run(_aioDnsController.Stop)
};
Task.WaitAll(tasks);
}
private void CheckDriver()
{
var binHash = Utils.Utils.SHA256CheckSum(BinDriver);
var sysHash = Utils.Utils.SHA256CheckSum(SysDriver);
string binDriver = Path.Combine(Global.NetchDir, @"bin\wintun.dll");
string sysDriver = $@"{Environment.SystemDirectory}\wintun.dll";
var binHash = Utils.Utils.SHA256CheckSum(binDriver);
var sysHash = Utils.Utils.SHA256CheckSum(sysDriver);
Global.Logger.Info("自带 wintun.dll Hash: " + binHash);
Global.Logger.Info("系统 wintun.dll Hash: " + sysHash);
if (binHash == sysHash)
@@ -113,7 +196,8 @@ namespace Netch.Controllers
try
{
File.Copy(BinDriver, SysDriver, true);
Global.Logger.Info("Copy wintun.dll to System Directory");
File.Copy(binDriver, sysDriver, true);
}
catch (Exception e)
{
@@ -121,190 +205,5 @@ namespace Netch.Controllers
throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}");
}
}
/// <summary>
/// TUN/TAP停止
/// </summary>
public void Stop()
{
var tasks = new[]
{
Task.Run(Free),
Task.Run(ClearRouteTable),
Task.Run(DNSController.Stop)
};
Task.WaitAll(tasks);
}
/// <summary>
/// 设置绕行规则
/// </summary>
/// <returns>是否设置成功</returns>
private void SetupRouteTable(Mode mode)
{
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
Global.Logger.Info("设置路由规则");
Global.Logger.Info("绕行 → 服务器 IP");
if (!IPAddress.IsLoopback(_serverAddresses))
RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound);
Global.Logger.Info("绕行 → 全局绕过 IP");
RouteAction(Action.Create, Global.Settings.TUNTAP.BypassIPs, RouteType.Outbound);
#region Rule IPs
switch (mode.Type)
{
case 1:
// 代理规则 IP
Global.Logger.Info("代理 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
if (Global.Settings.TUNTAP.ProxyDNS)
{
Global.Logger.Info("代理 → 自定义 DNS");
if (Global.Settings.TUNTAP.UseCustomDNS)
RouteAction(Action.Create, Global.Settings.TUNTAP.HijackDNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
else
RouteAction(Action.Create, $"{Global.Settings.AioDNS.OtherDNS}/32", RouteType.TUNTAP);
}
break;
case 2:
// 绕过规则 IP
Global.Logger.Info("绕行 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
break;
}
#endregion
if (mode.Type == 2)
{
Global.Logger.Info("代理 → 全局");
SetInterface(RouteType.TUNTAP, 0);
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP, record: false);
}
}
private void SetInterface(RouteType routeType, int? metric = null)
{
var adapter = routeType == RouteType.Outbound ? _outboundAdapter : _tunAdapter;
var arguments = $"interface ip set interface {adapter.InterfaceIndex} ";
if (metric != null)
arguments += $"metric={metric} ";
Utils.Utils.ProcessRunHiddenAsync("netsh", arguments).Wait();
}
/// <summary>
/// 清除绕行规则
/// </summary>
private bool ClearRouteTable()
{
var mode = MainController.Mode!;
RouteAction(Action.Delete, _directIPs, RouteType.Outbound);
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
_directIPs.Clear();
_proxyIPs.Clear();
if (mode.Type == 2)
{
SetInterface(RouteType.Outbound);
}
return true;
}
#region Package
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0, bool record = true)
{
foreach (var address in ipNetworks)
RouteAction(action, address, routeType, metric);
}
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0, bool record = true)
{
#region
if (!TryParseIPNetwork(ipNetwork, out var ip, out var cidr))
return false;
IAdapter adapter = routeType switch
{
RouteType.Outbound => _outboundAdapter,
RouteType.TUNTAP => _tunAdapter,
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
};
List<string> ipList = routeType switch
{
RouteType.Outbound => _directIPs,
RouteType.TUNTAP => _proxyIPs,
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
};
string gateway = adapter.Gateway.ToString();
var index = adapter.InterfaceIndex;
#endregion
bool result;
switch (action)
{
case Action.Create:
result = NativeMethods.CreateRoute((int) AddressFamily.InterNetwork, ip, cidr, gateway, index, metric);
if (result && record)
ipList.Add(ipNetwork);
break;
case Action.Delete:
result = NativeMethods.DeleteRoute((int) AddressFamily.InterNetwork, ip, cidr, gateway, index, metric);
break;
default:
throw new ArgumentOutOfRangeException(nameof(action), action, null);
}
Global.Logger.Debug($"{action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})");
if (!result)
Global.Logger.Warning($"Failed to invoke {action}Route(\"{ip}\", {cidr}, \"{gateway}\", {index}, {metric})");
return result;
}
bool TryParseIPNetwork(string ipNetwork, out string ip, out int cidr)
{
ip = null!;
cidr = 0;
var s = ipNetwork.Split('/');
if (s.Length != 2)
{
Global.Logger.Warning($"Failed to parse rule {ipNetwork}");
return false;
}
ip = s[0];
cidr = int.Parse(s[1]);
return true;
}
private enum RouteType
{
Outbound,
TUNTAP
}
private enum Action
{
Create,
Delete
}
#endregion
}
}

View File

@@ -1,4 +1,6 @@
using System;
using Netch.Models.GitHubRelease;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
@@ -6,8 +8,6 @@ using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Netch.Models.GitHubRelease;
using Netch.Utils;
namespace Netch.Controllers
{
@@ -19,8 +19,8 @@ namespace Netch.Controllers
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2021";
public const string AssemblyVersion = @"1.8.3";
private const string Suffix = @"Beta114514";
public const string AssemblyVersion = @"1.8.4";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
@@ -46,7 +46,7 @@ namespace Netch.Controllers
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
var releases = JsonSerializer.Deserialize<List<Release>>(json)!;
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
LatestRelease = GetLatestRelease(releases, isPreRelease);
Global.Logger.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
{
@@ -104,5 +104,14 @@ namespace Netch.Controllers
return sb.ToString();
}
public static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
{
if (!isPreRelease)
releases = releases.Where(release => !release.prerelease);
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionUtil.VersionComparer());
return ordered.ElementAt(0);
}
}
}
}

10
Netch/Enums/Modes.cs Normal file
View File

@@ -0,0 +1,10 @@
namespace Netch.Enums
{
public enum ModeType
{
Process = 0,
ProxyRuleIPs = 1,
BypassRuleIPs = 2,
Pcap2Socks = 6
}
}

View File

@@ -1,8 +1,8 @@
using System;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Diagnostics;
using System.Windows.Forms;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Forms
{
@@ -21,17 +21,17 @@ namespace Netch.Forms
private void NetchPictureBox_Click(object sender, EventArgs e)
{
Process.Start("https://github.com/NetchX/Netch");
Utils.Utils.Open("https://github.com/NetchX/Netch");
}
private void ChannelLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Process.Start("https://t.me/Netch");
Utils.Utils.Open("https://t.me/Netch");
}
private void SponsorPictureBox_Click(object sender, EventArgs e)
{
Process.Start("https://www.mansora.co");
Utils.Utils.Open("https://www.mansora.co");
}
}
}

View File

@@ -1,9 +1,9 @@
using System;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Forms
{
@@ -54,7 +54,7 @@ namespace Netch.Forms
{
Global.Settings.TUNTAP.BypassIPs.Clear();
foreach (var ip in IPListBox.Items)
Global.Settings.TUNTAP.BypassIPs.Add((string) ip);
Global.Settings.TUNTAP.BypassIPs.Add((string)ip);
Configuration.Save();
MessageBoxX.Show(i18N.Translate("Saved"));

View File

@@ -1,3 +1,9 @@
using Microsoft.Win32;
using Netch.Controllers;
using Netch.Forms.Mode;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -8,24 +14,13 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using Netch.Controllers;
using Netch.Forms.Mode;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using Netch.Enums;
using Netch.Interfaces;
namespace Netch.Forms
{
public partial class MainForm : Form
{
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
{
Hide();
new Route().ShowDialog();
Show();
}
#region Start
private readonly Dictionary<string, object> _mainFormText = new();
@@ -41,7 +36,7 @@ namespace Netch.Forms
#region i18N Translations
_mainFormText.Add(UninstallServiceToolStripMenuItem.Name, new[] {"Uninstall {0}", "NF Service"});
_mainFormText.Add(UninstallServiceToolStripMenuItem.Name, new[] { "Uninstall {0}", "NF Service" });
#endregion
@@ -60,10 +55,11 @@ namespace Netch.Forms
{
Name = $"Add{fullName}ServerToolStripMenuItem",
Size = new Size(259, 22),
Text = i18N.TranslateFormat("Add [{0}] Server", fullName)
Text = i18N.TranslateFormat("Add [{0}] Server", fullName),
Tag = serversUtil
};
_mainFormText.Add(control.Name, new[] {"Add [{0}] Server", fullName});
_mainFormText.Add(control.Name, new[] { "Add [{0}] Server", fullName });
control.Click += AddServerToolStripMenuItem_Click;
ServerToolStripMenuItem.DropDownItems.Add(control);
}
@@ -184,7 +180,7 @@ namespace Netch.Forms
return string.Empty;
if (value is object[] values)
return i18N.TranslateFormat((string) values.First(), values.Skip(1).ToArray());
return i18N.TranslateFormat((string)values.First(), values.Skip(1).ToArray());
return i18N.Translate(value);
}
@@ -227,15 +223,10 @@ namespace Netch.Forms
if (sender == null)
throw new ArgumentNullException(nameof(sender));
// TODO get Util from Tag
var s = ((ToolStripMenuItem) sender).Text;
var start = s.IndexOf("[", StringComparison.Ordinal) + 1;
var end = s.IndexOf("]", start, StringComparison.Ordinal);
var result = s.Substring(start, end - start);
var util = (IServerUtil)((ToolStripMenuItem)sender).Tag;
Hide();
ServerHelper.GetUtilByFullName(result).Create();
util.Create();
LoadServers();
Configuration.Save();
@@ -253,6 +244,13 @@ namespace Netch.Forms
Show();
}
private void createRouteTableModeToolStripMenuItem_Click(object sender, EventArgs e)
{
Hide();
new Route().ShowDialog();
Show();
}
#endregion
#region Subscription
@@ -348,7 +346,7 @@ namespace Netch.Forms
{
await Task.Run(() =>
{
NativeMethods.FlushDNSResolverCache();
NativeMethods.RefreshDNSCache();
DnsUtils.ClearCache();
});
@@ -704,7 +702,7 @@ namespace Netch.Forms
{
try
{
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode) ModeComboBox.SelectedItem);
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode)ModeComboBox.SelectedItem);
}
catch
{
@@ -721,7 +719,7 @@ namespace Netch.Forms
return;
}
var mode = (Models.Mode) ModeComboBox.SelectedItem;
var mode = (Models.Mode)ModeComboBox.SelectedItem;
if (ModifierKeys == Keys.Control)
{
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath!));
@@ -730,13 +728,13 @@ namespace Netch.Forms
switch (mode.Type)
{
case 0:
case ModeType.Process:
Hide();
new Process(mode).ShowDialog();
Show();
break;
case 1:
case 2:
case ModeType.ProxyRuleIPs:
case ModeType.BypassRuleIPs:
Hide();
new Route(mode).ShowDialog();
Show();
@@ -756,7 +754,7 @@ namespace Netch.Forms
return;
}
ModeHelper.Delete((Models.Mode) ModeComboBox.SelectedItem);
ModeHelper.Delete((Models.Mode)ModeComboBox.SelectedItem);
SelectLastMode();
}
@@ -773,7 +771,7 @@ namespace Netch.Forms
{
// Clear
foreach (var button in ProfileTable.Controls)
((Button) button).Dispose();
((Button)button).Dispose();
ProfileTable.Controls.Clear();
ProfileTable.ColumnStyles.Clear();
@@ -799,7 +797,7 @@ namespace Netch.Forms
var columnCount = Global.Settings.ProfileTableColumnCount;
ProfileTable.ColumnCount = profileCount >= columnCount ? columnCount : profileCount;
ProfileTable.RowCount = (int) Math.Ceiling(profileCount / (float) columnCount);
ProfileTable.RowCount = (int)Math.Ceiling(profileCount / (float)columnCount);
for (var i = 0; i < profileCount; ++i)
{
@@ -848,8 +846,8 @@ namespace Netch.Forms
private Profile CreateProfileAtIndex(int index)
{
var server = (Server) ServerComboBox.SelectedItem;
var mode = (Models.Mode) ModeComboBox.SelectedItem;
var server = (Server)ServerComboBox.SelectedItem;
var mode = (Models.Mode)ModeComboBox.SelectedItem;
var name = ProfileNameText.Text;
Profile? profile;
@@ -866,8 +864,8 @@ namespace Netch.Forms
if (sender == null)
throw new ArgumentNullException(nameof(sender));
var profileButton = (Button) sender;
var profile = (Profile?) profileButton.Tag;
var profileButton = (Button)sender;
var profile = (Profile?)profileButton.Tag;
var index = ProfileTable.Controls.IndexOf(profileButton);
switch (ModifierKeys)
@@ -1107,13 +1105,13 @@ namespace Netch.Forms
{
NatTypeStatusLightLabel.Visible = Flags.IsWindows10Upper;
var c = natType switch
{
1 => Color.LimeGreen,
2 => Color.Yellow,
3 => Color.Red,
4 => Color.Black,
_ => throw new ArgumentOutOfRangeException(nameof(natType), natType, null)
};
{
1 => Color.LimeGreen,
2 => Color.Yellow,
3 => Color.Red,
4 => Color.Black,
_ => throw new ArgumentOutOfRangeException(nameof(natType), natType, null)
};
NatTypeStatusLightLabel.ForeColor = c;
}
@@ -1231,11 +1229,11 @@ namespace Netch.Forms
Configuration.Save();
}
foreach (var file in new[] {"data\\last.json", "data\\privoxy.conf"})
foreach (var file in new[] { "data\\last.json", "data\\privoxy.conf" })
if (File.Exists(file))
File.Delete(file);
if (IsWaiting())
if (!IsWaiting())
await StopAsyncCore();
Dispose();
@@ -1403,7 +1401,7 @@ namespace Netch.Forms
case Server item:
{
// 计算延迟底色
var numBoxBackBrush = item.Delay switch {> 200 => Brushes.Red, > 80 => Brushes.Yellow, >= 0 => _greenBrush, _ => Brushes.Gray};
var numBoxBackBrush = item.Delay switch { > 200 => Brushes.Red, > 80 => Brushes.Yellow, >= 0 => _greenBrush, _ => Brushes.Gray };
// 绘制延迟底色
e.Graphics.FillRectangle(numBoxBackBrush, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
@@ -1425,7 +1423,7 @@ namespace Netch.Forms
// 绘制 模式行数 字符串
TextRenderer.DrawText(e.Graphics,
item.Rule.Count.ToString(),
item.Content.Count.ToString(),
cbx.Font,
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
Color.Black,

View File

@@ -1,7 +1,7 @@
using System;
using System.Windows.Forms;
using Netch.Models;
using Netch.Models;
using Netch.Utils;
using System;
using System.Windows.Forms;
namespace Netch.Forms
{
@@ -23,20 +23,20 @@ namespace Netch.Forms
MessageBoxIcon msgIcon;
if (string.IsNullOrWhiteSpace(title))
title = level switch
{
LogLevel.INFO => "Information",
LogLevel.WARNING => "Warning",
LogLevel.ERROR => "Error",
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
};
{
LogLevel.INFO => "Information",
LogLevel.WARNING => "Warning",
LogLevel.ERROR => "Error",
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
};
msgIcon = level switch
{
LogLevel.INFO => MessageBoxIcon.Information,
LogLevel.WARNING => MessageBoxIcon.Warning,
LogLevel.ERROR => MessageBoxIcon.Exclamation,
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
};
{
LogLevel.INFO => MessageBoxIcon.Information,
LogLevel.WARNING => MessageBoxIcon.Warning,
LogLevel.ERROR => MessageBoxIcon.Exclamation,
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
};
return MessageBox.Show(owner, text, i18N.Translate(title), confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK, msgIcon);
}

View File

@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Dialogs;
using Microsoft.WindowsAPICodePack.Dialogs;
using Netch.Controllers;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Netch.Enums;
namespace Netch.Forms.Mode
{
@@ -24,7 +25,7 @@ namespace Netch.Forms.Mode
/// <param name="mode">模式</param>
public Process(Models.Mode? mode = null)
{
if (mode != null && mode.Type is not 0)
if (mode != null && mode.Type is not ModeType.Process)
throw new ArgumentOutOfRangeException();
InitializeComponent();
@@ -62,7 +63,7 @@ namespace Netch.Forms.Mode
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
RemarkTextBox.Text = _mode.Remark;
FilenameTextBox.Text = _mode.RelativePath;
RuleAddRange(_mode.Rule);
RuleAddRange(_mode.Content);
}
i18N.TranslateForm(this);
@@ -116,8 +117,8 @@ namespace Netch.Forms.Mode
if (_mode != null)
{
_mode.Remark = RemarkTextBox.Text;
_mode.Rule.Clear();
_mode.Rule.AddRange(RuleRichTextBox.Lines);
_mode.Content.Clear();
_mode.Content.AddRange(RuleRichTextBox.Lines);
_mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
@@ -134,11 +135,11 @@ namespace Netch.Forms.Mode
var mode = new Models.Mode(fullName)
{
Type = 0,
Type = ModeType.Process,
Remark = RemarkTextBox.Text
};
mode.Rule.AddRange(RuleRichTextBox.Lines);
mode.Content.AddRange(RuleRichTextBox.Lines);
mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode added successfully"));

View File

@@ -1,21 +1,23 @@
using System;
using System.IO;
using System.Windows.Forms;
using Netch.Models;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.IO;
using System.Windows.Forms;
using Netch.Enums;
namespace Netch.Forms.Mode
{
public partial class Route : Form
{
private readonly TagItem<int>[] _items = {new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs")};
private readonly TagItem<ModeType>[] _items =
{ new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") };
private readonly Models.Mode? _mode;
public Route(Models.Mode? mode = null)
{
if (mode != null && mode.Type is not (1 or 2))
if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs))
throw new ArgumentOutOfRangeException();
_mode = mode;
@@ -37,7 +39,7 @@ namespace Netch.Forms.Mode
RemarkTextBox.Text = _mode.Remark;
comboBox1.SelectedValue = _mode.Type; // ComboBox SelectedValue worked after ctor
FilenameTextBox.Text = _mode.RelativePath;
richTextBox1.Lines = _mode.Rule.ToArray();
richTextBox1.Lines = _mode.Content.ToArray();
}
i18N.TranslateForm(this);
@@ -60,9 +62,9 @@ namespace Netch.Forms.Mode
if (_mode != null)
{
_mode.Remark = RemarkTextBox.Text;
_mode.Rule.Clear();
_mode.Rule.AddRange(richTextBox1.Lines);
_mode.Type = (int) comboBox1.SelectedValue;
_mode.Content.Clear();
_mode.Content.AddRange(richTextBox1.Lines);
_mode.Type = (ModeType)comboBox1.SelectedValue;
_mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
@@ -79,11 +81,11 @@ namespace Netch.Forms.Mode
var mode = new Models.Mode(fullName)
{
Type = (int) comboBox1.SelectedValue,
Type = (ModeType)comboBox1.SelectedValue,
Remark = RemarkTextBox.Text
};
mode.Rule.AddRange(richTextBox1.Lines);
mode.Content.AddRange(richTextBox1.Lines);
mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode added successfully"));

View File

@@ -1,13 +1,13 @@
#nullable disable
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Forms
{
@@ -38,13 +38,13 @@ namespace Netch.Forms
InitializeComponent();
_checkActions.Add(RemarkTextBox, s => true);
_saveActions.Add(RemarkTextBox, s => Server.Remark = (string) s);
_saveActions.Add(RemarkTextBox, s => Server.Remark = (string)s);
_checkActions.Add(AddressTextBox, s => s != string.Empty);
_saveActions.Add(AddressTextBox, s => Server.Hostname = (string) s);
_saveActions.Add(AddressTextBox, s => Server.Hostname = (string)s);
_checkActions.Add(PortTextBox, s => ushort.TryParse(s, out var port) && port != 0);
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string) s));
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string)s));
}
protected abstract string TypeName { get; }
@@ -99,7 +99,7 @@ namespace Netch.Forms
};
_checkActions.Add(textBox, check);
_saveActions.Add(textBox, o => save.Invoke((string) o));
_saveActions.Add(textBox, o => save.Invoke((string)o));
ConfigurationGroupBox.Controls.AddRange(new Control[]
{
textBox,
@@ -131,7 +131,7 @@ namespace Netch.Forms
comboBox.Items.AddRange(values.ToArray());
comboBox.SelectedIndex = values.IndexOf(value);
comboBox.DrawItem += Utils.Utils.DrawCenterComboBox;
_saveActions.Add(comboBox, o => save.Invoke((string) o));
_saveActions.Add(comboBox, o => save.Invoke((string)o));
ConfigurationGroupBox.Controls.AddRange(new Control[]
{
comboBox,
@@ -159,7 +159,7 @@ namespace Netch.Forms
Text = remark
};
_saveActions.Add(checkBox, o => save.Invoke((bool) o));
_saveActions.Add(checkBox, o => save.Invoke((bool)o));
ConfigurationGroupBox.Controls.AddRange(new Control[]
{
checkBox

View File

@@ -1,3 +1,6 @@
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -5,9 +8,6 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Forms
{
@@ -37,7 +37,7 @@ namespace Netch.Forms
BindCheckBox(AllowDevicesCheckBox,
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
Global.Settings.LocalAddress switch {"127.0.0.1" => false, "0.0.0.0" => true, _ => false});
Global.Settings.LocalAddress switch { "127.0.0.1" => false, "0.0.0.0" => true, _ => false });
BindCheckBox(ResolveServerHostnameCheckBox, c => Global.Settings.ResolveServerHostname = c, Global.Settings.ResolveServerHostname);
@@ -116,7 +116,7 @@ namespace Netch.Forms
Global.Settings.Redirector.ChildProcessHandle);
BindListComboBox(ProcessProxyProtocolComboBox,
s => Global.Settings.Redirector.ProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
s => Global.Settings.Redirector.ProxyProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
Enum.GetNames(typeof(PortType)),
Global.Settings.Redirector.ProxyProtocol.ToString());
@@ -284,7 +284,7 @@ namespace Netch.Forms
{
try
{
return check.Invoke((T) Convert.ChangeType(s, typeof(T)));
return check.Invoke((T)Convert.ChangeType(s, typeof(T)));
}
catch
{
@@ -292,19 +292,19 @@ namespace Netch.Forms
}
});
_saveActions.Add(control, c => save.Invoke((T) Convert.ChangeType(((TextBox) c).Text, typeof(T))));
_saveActions.Add(control, c => save.Invoke((T)Convert.ChangeType(((TextBox)c).Text, typeof(T))));
}
private void BindCheckBox(CheckBox control, Action<bool> save, bool value)
{
control.Checked = value;
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
_saveActions.Add(control, c => save.Invoke(((CheckBox)c).Checked));
}
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
{
control.Checked = value;
_saveActions.Add(control, c => save.Invoke(((RadioButton) c).Checked));
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
}
private void BindListComboBox<T>(ComboBox comboBox, Action<T> save, IEnumerable<T> values, T value) where T : notnull
@@ -318,7 +318,7 @@ namespace Netch.Forms
comboBox.ValueMember = nameof(TagItem<T>.Value);
comboBox.DisplayMember = nameof(TagItem<T>.Text);
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>) ((ComboBox) c).SelectedItem).Value));
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>)((ComboBox)c).SelectedItem).Value));
Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); };
}
@@ -327,7 +327,7 @@ namespace Netch.Forms
if (values != null)
control.Items.AddRange(values);
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).Text));
_saveActions.Add(control, c => save.Invoke(((ComboBox)c).Text));
_checkActions.Add(control, check.Invoke);
Load += (_, _) => { control.Text = value; };

View File

@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Windows.Forms;
using Netch.Models;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Linq;
using System.Windows.Forms;
namespace Netch.Forms
{

View File

@@ -1,12 +1,12 @@
using Netch.Forms;
using Netch.Interfaces;
using Netch.Models;
using Netch.Models.Loggers;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Windows.Forms;
using Netch.Forms;
using Netch.Interfaces;
using Netch.Models;
using Netch.Models.Loggers;
namespace Netch
{

View File

@@ -1,4 +1,4 @@
namespace Netch.Controllers
namespace Netch.Interfaces
{
public interface IController
{

View File

@@ -1,6 +1,6 @@
using Netch.Models;
namespace Netch.Controllers
namespace Netch.Interfaces
{
public interface IModeController : IController
{

View File

@@ -1,6 +1,6 @@
using Netch.Models;
namespace Netch.Controllers
namespace Netch.Interfaces
{
public interface IServerController : IController
{

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
namespace Netch.Models
namespace Netch.Interfaces
{
public interface IServerUtil
{
@@ -28,7 +28,7 @@ namespace Netch.Models
/// </summary>
string[] UriScheme { get; }
public abstract Type ServerType { get; }
public Type ServerType { get; }
public void Edit(Server s);
@@ -36,9 +36,9 @@ namespace Netch.Models
string GetShareLink(Server s);
public abstract IServerController GetController();
public IServerController GetController();
public abstract IEnumerable<Server> ParseUri(string text);
public IEnumerable<Server> ParseUri(string text);
bool CheckServer(Server s);
}

View File

@@ -3,7 +3,7 @@ using System.Text;
namespace Netch.Interops
{
public static class AioDNSInterops
public static class AioDNS
{
private const string aiodns_bin = "aiodns.bin";

View File

@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace Netch.Interops
{

View File

@@ -1,9 +1,8 @@
using System.Runtime.InteropServices;
using Netch.Utils;
namespace Netch.Interops
{
public static class RedirectorInterop
public static class Redirector
{
public enum NameList
{
@@ -57,7 +56,7 @@ namespace Netch.Interops
return aio_free();
}
public const int UdpNameListOffset = (int) NameList.TYPE_UDPLISN - (int) NameList.TYPE_TCPLISN;
public const int UdpNameListOffset = (int)NameList.TYPE_UDPLISN - (int)NameList.TYPE_TCPLISN;
private const string Redirector_bin = "Redirector.bin";

View 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);
}
}

View File

@@ -1,10 +1,9 @@
using System.Runtime.InteropServices;
using System.Text;
using Netch.Utils;
namespace Netch.Interops
{
public static class TUNInterop
public static class tun2socks
{
public enum NameList
{
@@ -42,6 +41,7 @@ namespace Netch.Interops
public static bool Init()
{
Global.Logger.Debug("tun2socks init");
return tun_init();
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace Netch.Models.GitHubRelease
{
@@ -8,28 +9,53 @@ namespace Netch.Models.GitHubRelease
{
public Version Version { get; }
public string Suffix { get; }
public string? Suffix { get; }
public SuffixVersion(Version version, string suffix)
public int SuffixNum { get; }
private SuffixVersion(Version version)
{
Version = version;
Suffix = null;
SuffixNum = 0;
}
private SuffixVersion(Version version, string suffix, int suffixNum)
{
Version = version;
Suffix = suffix;
SuffixNum = suffixNum;
}
public static SuffixVersion Parse(string? input)
public static SuffixVersion Parse(string? value)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (value == null)
throw new ArgumentNullException(nameof(value));
var split = input.Split('-');
var dotNetVersion = Version.Parse(split[0]);
var preRelease = split.ElementAtOrDefault(1) ?? string.Empty;
var strings = value.Split('-');
return new SuffixVersion(dotNetVersion, preRelease);
var version = Version.Parse(strings[0]);
var suffix = strings.ElementAtOrDefault(1)?.Trim();
switch (suffix)
{
case null:
return new SuffixVersion(version);
case "":
throw new Exception("suffix WhiteSpace");
default:
{
var match = Regex.Match(suffix, @"(?<suffix>\D+)(?<num>\d+)");
if (!match.Success)
throw new Exception();
return new SuffixVersion(version, match.Groups["suffix"].Value, int.Parse(match.Groups["num"].Value));
}
}
}
public static bool TryParse(string input, out SuffixVersion result)
public static bool TryParse(string? input, out SuffixVersion result)
{
result = default;
try
{
result = Parse(input);
@@ -37,7 +63,6 @@ namespace Netch.Models.GitHubRelease
}
catch (Exception)
{
result = default;
return false;
}
}
@@ -62,21 +87,22 @@ namespace Netch.Models.GitHubRelease
if (versionComparison != 0)
return versionComparison;
if (Suffix == string.Empty)
return other.Suffix == string.Empty ? 0 : 1;
if (other.Suffix == string.Empty)
return -1;
var suffixExistComparison = (Suffix == null ? 1 : 0) - (other.Suffix == null ? 1 : 0);
if (suffixExistComparison != 0)
return suffixExistComparison;
var suffixComparison = string.Compare(Suffix, other.Suffix, StringComparison.OrdinalIgnoreCase);
return suffixComparison;
if (suffixComparison != 0)
return suffixComparison;
return SuffixNum - other.SuffixNum;
}
public override string ToString()
{
var s = Version.ToString();
if (Suffix != string.Empty)
s += $"-{Suffix}";
if (Suffix != null)
s += $"-{Suffix}{SuffixNum}";
return s;
}

View File

@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
namespace Netch.Models.GitHubRelease
{
public class VersionComparer : IComparer<object>
{
public int Compare(object? x, object? y)
{
if (x == null)
throw new ArgumentNullException(nameof(x));
if (y == null)
throw new ArgumentNullException(nameof(y));
return VersionUtil.CompareVersion(x.ToString(), y.ToString());
}
}
}

View File

@@ -1,33 +1,37 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Netch.Models.GitHubRelease
{
public static class VersionUtil
{
public static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
{
if (!isPreRelease)
releases = releases.Where(release => !release.prerelease);
private static VersionComparer instance = new();
releases = releases.Where(release => IsVersionString(release.tag_name));
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionComparer());
return ordered.ElementAt(0);
public static int CompareVersion(string x, string y)
{
return instance.Compare(x, y);
}
private static bool IsVersionString(string str)
public class VersionComparer : IComparer<string>
{
return SuffixVersion.TryParse(str, out _);
}
/// <summary>
/// Greater than 0 newer
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public int Compare(string? x, string? y)
{
var xResult = SuffixVersion.TryParse(x, out var version1) ? 1 : 0;
var yResult = SuffixVersion.TryParse(y, out var version2) ? 1 : 0;
/// <returns> =0:versions are equal</returns>
/// <returns> &gt;0:version1 is greater</returns>
/// <returns> &lt;0:version2 is greater</returns>
public static int CompareVersion(string? v1, string? v2)
{
var version1 = SuffixVersion.Parse(v1);
var version2 = SuffixVersion.Parse(v2);
return version1.CompareTo(version2);
var parseResult = xResult - yResult;
if (parseResult != 0)
return parseResult;
return version1.CompareTo(version2);
}
}
}
}

View File

@@ -1,14 +0,0 @@
using System.Net;
using System.Net.NetworkInformation;
namespace Netch.Models
{
public interface IAdapter
{
int InterfaceIndex { get; }
IPAddress Gateway { get; }
NetworkInterface NetworkInterface { get; }
}
}

View File

@@ -1,5 +1,5 @@
using System;
using Netch.Interfaces;
using Netch.Interfaces;
using System;
namespace Netch.Models.Loggers
{

View File

@@ -1,12 +1,12 @@
using System;
using Netch.Interfaces;
using System;
using System.IO;
using Netch.Interfaces;
namespace Netch.Models.Loggers
{
public class FileLogger : ILogger
{
public string LogFile { get; set; }= Path.Combine(Global.NetchDir, "logging\\application.log");
public string LogFile { get; set; } = Path.Combine(Global.NetchDir, "logging\\application.log");
private readonly object _fileLock = new();

View File

@@ -1,141 +1,129 @@
using System;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Netch.Utils;
using Netch.Enums;
namespace Netch.Models
{
public class Mode
{
private readonly Lazy<List<string>> _lazyRule;
public string? FullName { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="fullName">Mode File FullPath</param>
/// <exception cref="FormatException"></exception>
/// <exception cref="NotSupportedException"></exception>
public Mode(string? fullName)
{
_lazyRule = new Lazy<List<string>>(ReadRules);
if (fullName == null)
return;
FullName = fullName;
if (!File.Exists(FullName))
if (FullName == null || !File.Exists(FullName))
return;
var text = File.ReadLines(FullName).First();
// load head
if (text.First() != '#')
throw new Exception($"mode {FullName} head not found at Line 0");
var split = text.Substring(1).SplitTrimEntries(',');
Remark = split[0];
var typeResult = int.TryParse(split.ElementAtOrDefault(1), out var type);
Type = typeResult ? type : 0;
if (!ModeHelper.ModeTypes.Contains(Type))
throw new NotSupportedException($"not support mode \"[{Type}]{Remark}\".");
(Remark, Type) = ReadHead(FullName);
}
public string? FullName { get; }
/// <summary>
/// 规则
/// </summary>
public List<string> Rule => _lazyRule.Value;
public List<string> Content => _content ??= ReadContent();
private List<string>? _content;
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; } = "";
/// <summary>
/// 类型
/// <para />
/// 0. Socks5 + 进程加速
/// <para />
/// 1. Socks5 + TUN/TAP 规则内 IP CIDR 加速
/// <para />
/// 2. Socks5 + TUN/TAP 全局,绕过规则内 IP CIDR
/// <para />
/// 3. Socks5 + HTTP 代理(设置到系统代理)
/// <para />
/// 4. Socks5 代理(不设置到系统代理)
/// <para />
/// 5. Socks5 + HTTP 代理(不设置到系统代理)
/// <para />
/// </summary>
public int Type { get; set; } = 0;
public ModeType Type { get; set; } = ModeType.Process;
/// <summary>
/// 文件相对路径(必须是存在的文件)
/// </summary>
public string? RelativePath => FullName == null ? null : ModeHelper.GetRelativePath(FullName);
public List<string> FullRule
public IEnumerable<string> GetRules()
{
get
var result = new List<string>();
foreach (var s in Content)
{
var result = new List<string>();
foreach (var s in Rule)
if (string.IsNullOrWhiteSpace(s))
continue;
if (s.StartsWith("//"))
continue;
const string include = "#include";
if (s.StartsWith(include))
{
if (string.IsNullOrWhiteSpace(s))
continue;
var relativePath = new StringBuilder(s[include.Length..].Trim());
relativePath.Replace("<", "").Replace(">", "");
relativePath.Replace(".h", ".txt");
if (s.StartsWith("//"))
continue;
var mode = Global.Modes.FirstOrDefault(m => m.RelativePath?.Equals(relativePath.ToString()) ?? false) ??
throw new MessageException($"{relativePath} file included in {Remark} not found");
if (s.StartsWith("#include"))
{
var relativePath = new StringBuilder(s.Substring(8).Trim());
relativePath.Replace("<", "");
relativePath.Replace(">", "");
relativePath.Replace(".h", ".txt");
if (mode == this)
throw new MessageException("Can't self-reference");
var mode = Global.Modes.FirstOrDefault(m => m.FullName != null && m.RelativePath!.Equals(relativePath.ToString()));
if (mode.Type != Type)
throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
if (mode == null)
throw new MessageException($"{relativePath} file included in {Remark} not found");
if (mode.Content.Any(rule => rule.StartsWith(include)))
throw new Exception("Cannot reference mode that reference other mode");
if (mode == this)
throw new MessageException("Can't self-reference");
if (mode.Type != Type)
throw new MessageException($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
if (mode.Rule.Any(rule => rule.StartsWith("#include")))
throw new Exception("Cannot reference mode that reference other mode");
result.AddRange(mode.FullRule);
}
else
{
result.Add(s);
}
result.AddRange(mode.GetRules());
}
else
{
result.Add(s);
}
return result;
}
return result;
}
private List<string> ReadRules()
private static (string, ModeType) ReadHead(string fileName)
{
var text = File.ReadLines(fileName).First();
if (text.First() != '#')
throw new FormatException($"{fileName} head not found at Line 0");
var split = text[1..].SplitTrimEntries(',');
var typeNumber = int.TryParse(split.ElementAtOrDefault(1), out var type) ? type : 0;
if (!Enum.GetValues(typeof(ModeType)).Cast<int>().Contains(typeNumber))
throw new NotSupportedException($"Not support mode \"{typeNumber}\".");
return (split[0], (ModeType)typeNumber);
}
private List<string> ReadContent()
{
if (FullName == null || !File.Exists(FullName))
return new List<string>();
return File.ReadLines(FullName!).Skip(1).ToList();
return File.ReadLines(FullName).Skip(1).ToList();
}
public void WriteFile(string? fullName = null)
public void ResetContent()
{
if (fullName != null)
throw new NotImplementedException();
_content = null;
}
public void WriteFile()
{
var dir = Path.GetDirectoryName(FullName)!;
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
var content = $"# {Remark}, {(int)Type}{Constants.EOF}{string.Join(Constants.EOF, Content)}";
// 写入到模式文件里
File.WriteAllText(FullName!, ToFileString());
File.WriteAllText(FullName!, content);
}
/// <summary>
@@ -144,16 +132,7 @@ namespace Netch.Models
/// <returns>备注</returns>
public override string ToString()
{
return $"[{Type + 1}] {i18N.Translate(Remark)}";
}
/// <summary>
/// 获取模式文件字符串
/// </summary>
/// <returns>模式文件字符串</returns>
public string ToFileString()
{
return $"# {Remark}, {Type}{Constants.EOF}{string.Join(Constants.EOF, Rule)}";
return $"[{(int)Type + 1}] {i18N.Translate(Remark)}";
}
}
@@ -162,7 +141,7 @@ namespace Netch.Models
/// 是否会转发 UDP
public static bool TestNatRequired(this Mode mode)
{
return mode.Type is 0 or 2;
return mode.Type is ModeType.Process or ModeType.BypassRuleIPs;
}
}
}

50
Netch/Models/NetRoute.cs Normal file
View File

@@ -0,0 +1,50 @@
using System;
using System.Net;
using Vanara.PInvoke;
namespace Netch.Models
{
public struct NetRoute
{
public static NetRoute TemplateBuilder(string gateway, int interfaceIndex, int metric = 0)
{
return new()
{
Gateway = gateway,
InterfaceIndex = interfaceIndex,
Metric = metric
};
}
public static (NetRoute, IPAddress address) GetBestRouteTemplate()
{
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var route) != 0)
throw new MessageException("GetBestRoute 搜索失败");
var address = new IPAddress(route.dwForwardNextHop.S_addr);
var gateway = new IPAddress(route.dwForwardNextHop.S_un_b);
return (TemplateBuilder(gateway.ToString(), (int)route.dwForwardIfIndex), address);
}
public int InterfaceIndex;
public string Gateway;
public string Network;
public byte Cidr;
public int Metric;
public NetRoute FillTemplate(string network, byte cidr, int? metric = null)
{
var o = (NetRoute)MemberwiseClone();
o.Network = network;
o.Cidr = cidr;
if (metric != null)
o.Metric = (int)metric;
return o;
}
}
}

View File

@@ -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;

View File

@@ -1,46 +0,0 @@
using System;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using Netch.Utils;
using Vanara.PInvoke;
namespace Netch.Models
{
public class OutboundAdapter : IAdapter
{
public OutboundAdapter()
{
// 寻找出口适配器
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0)
{
throw new MessageException("GetBestRoute 搜索失败");
}
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces()
.First(ni => ni.Supports(NetworkInterfaceComponent.IPv4) &&
ni.GetIPProperties().GetIPv4Properties().Index == pRoute.dwForwardIfIndex);
Address = new IPAddress(pRoute.dwForwardNextHop.S_addr);
InterfaceIndex = (int) pRoute.dwForwardIfIndex;
Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
Global.Logger.Info($"出口 网关 地址:{Gateway}");
Global.Logger.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
}
public IPAddress Address { get; }
/// <summary>
/// 索引
/// </summary>
public int InterfaceIndex { get; }
/// <summary>
/// 网关
/// </summary>
public IPAddress Gateway { get; }
public NetworkInterface NetworkInterface { get; }
}
}

View File

@@ -1,8 +1,8 @@
using System;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Netch.Utils;
namespace Netch.Models
{

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Utils;
using Netch.Utils;
using System.Collections.Generic;
namespace Netch.Models
{
@@ -265,7 +265,7 @@ namespace Netch.Models
public Setting Clone()
{
return (Setting) MemberwiseClone();
return (Setting)MemberwiseClone();
}
public void Set(Setting value)

View File

@@ -1,6 +1,6 @@
using Netch.Utils;
using System.Collections.Generic;
using System.Linq;
using Netch.Utils;
namespace Netch.Models
{

View File

@@ -1,27 +0,0 @@
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using Netch.Interops;
using Netch.Utils;
namespace Netch.Models
{
public class TunAdapter : IAdapter
{
public TunAdapter()
{
InterfaceIndex = (int) NativeMethods.ConvertLuidToIndex(TUNInterop.tun_luid());
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.GetIPProperties().GetIPv4Properties().Index == InterfaceIndex);
Gateway = IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
Global.Logger.Info($"WinTUN 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
}
public int InterfaceIndex { get; }
public IPAddress Gateway { get; }
public NetworkInterface NetworkInterface { get; }
}
}

View File

@@ -4,47 +4,7 @@ namespace Netch
{
public static class NativeMethods
{
/// <summary>
/// 分配 IP 地址
/// </summary>
/// <param name="inet">AF_INET / AF_INET6</param>
/// <param name="address">目标地址</param>
/// <param name="cidr">CIDR</param>
/// <param name="index">适配器索引</param>
/// <returns>是否成功</returns>
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateUnicastIP")]
public static extern bool CreateUnicastIP(int inet, string address, int cidr, int index);
/// <summary>
/// 创建路由规则
/// </summary>
/// <param name="inet">AF_INET / AF_INET6</param>
/// <param name="address">目标地址</param>
/// <param name="cidr">CIDR</param>
/// <param name="gateway">网关地址</param>
/// <param name="index">适配器索引</param>
/// <param name="metric">跃点数</param>
/// <returns>是否成功</returns>
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateRoute")]
public static extern bool CreateRoute(int inet, string address, int cidr, string gateway, int index, int metric = 0);
/// <summary>
/// 删除路由规则
/// </summary>
/// <param name="inet">AF_INET / AF_INET6</param>
/// <param name="address">目标地址</param>
/// <param name="cidr">掩码地址</param>
/// <param name="gateway">网关地址</param>
/// <param name="index">适配器索引</param>
/// <param name="metric">跃点数</param>
/// <returns>是否成功</returns>
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
public static extern bool DeleteRoute(int inet, string address, int cidr, string gateway, int index, int metric = 0);
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong ConvertLuidToIndex(ulong luid);
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();
public static extern uint RefreshDNSCache();
}
}
}

View File

@@ -1,13 +1,13 @@
using System;
using Netch.Controllers;
using Netch.Forms;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Forms;
using Netch.Utils;
using static Vanara.PInvoke.Kernel32;
namespace Netch
@@ -41,7 +41,7 @@ namespace Netch
Updater.Updater.CleanOld(Global.NetchDir);
// 预创建目录
var directories = new[] {"mode\\Custom", "data", "i18n", "logging"};
var directories = new[] { "mode\\Custom", "data", "i18n", "logging" };
foreach (var item in directories)
if (!Directory.Exists(item))
Directory.CreateDirectory(item);

View File

@@ -1,5 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
@@ -39,32 +38,22 @@
<ItemGroup>
<PackageReference Include="HMBSbige.SingleInstance" Version="5.0.0" />
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.68" GeneratePathProperty="true" />
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.2.4089">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
<PackageReference Include="System.Management" Version="5.0.0" />
<PackageReference Include="TaskScheduler" Version="2.9.1" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.7" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.9" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.7" />
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.9" />
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<None Remove=".gitignore" />
<None Visible="false" Include="..\binaries\**" LinkBase="bin" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
<None Update="..\binaries\NTT.exe">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
<None Remove="..\binaries\.git" />
<None Visible="false" Include="..\translations\i18n\**" LinkBase="i18n" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
<None Visible="false" Include="..\modes\mode\**" LinkBase="mode" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
@@ -100,5 +89,4 @@
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\TraceReloggerLib.dll" />
</ItemGroup>
</Target>
</Project>

View File

@@ -1,6 +1,6 @@
using System.Reflection;
using Netch.Controllers;
using System.Reflection;
using System.Runtime.InteropServices;
using Netch.Controllers;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
namespace Netch.Servers.Shadowsocks
@@ -8,9 +9,9 @@ namespace Netch.Servers.Shadowsocks
{
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"listening at"};
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "listening at" };
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"Invalid config path", "usage", "plugin service exit unexpectedly"};
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "Invalid config path", "usage", "plugin service exit unexpectedly" };
public override string Name { get; } = "Shadowsocks";
@@ -20,7 +21,7 @@ namespace Netch.Servers.Shadowsocks
public void Start(in Server s, in Mode mode)
{
var server = (Shadowsocks) s;
var server = (Shadowsocks)s;
var command = new SSParameter
{

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Shadowsocks.Form;
using Netch.Servers.Shadowsocks.Models.SSD;
@@ -22,13 +22,13 @@ namespace Netch.Servers.Shadowsocks
public string ShortName { get; } = "SS";
public string[] UriScheme { get; } = {"ss", "ssd"};
public string[] UriScheme { get; } = { "ss", "ssd" };
public Type ServerType { get; } = typeof(Shadowsocks);
public void Edit(Server s)
{
new ShadowsocksForm((Shadowsocks) s).ShowDialog();
new ShadowsocksForm((Shadowsocks)s).ShowDialog();
}
public void Create()
@@ -38,7 +38,7 @@ namespace Netch.Servers.Shadowsocks
public string GetShareLink(Server s)
{
var server = (Shadowsocks) s;
var server = (Shadowsocks)s;
// ss://method:password@server:port#Remark
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" +
HttpUtility.UrlEncode(server.Remark);
@@ -52,7 +52,7 @@ namespace Netch.Servers.Shadowsocks
public IEnumerable<Server> ParseUri(string text)
{
if (text.StartsWith("ss://"))
return new[] {ParseSsUri(text)};
return new[] { ParseSsUri(text) };
if (text.StartsWith("ssd://"))
return ParseSsdUri(text);
@@ -62,7 +62,7 @@ namespace Netch.Servers.Shadowsocks
public bool CheckServer(Server s)
{
var server = (Shadowsocks) s;
var server = (Shadowsocks)s;
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
{
Global.Logger.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
@@ -79,17 +79,17 @@ namespace Netch.Servers.Shadowsocks
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
return json.servers.Select(server => new Shadowsocks
{
Remark = server.remarks,
Hostname = server.server,
Port = server.port != 0 ? server.port : json.port,
Password = server.password ?? json.password,
EncryptMethod = server.encryption ?? json.encryption,
Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin,
PluginOption = string.IsNullOrEmpty(json.plugin_options)
{
Remark = server.remarks,
Hostname = server.server,
Port = server.port != 0 ? server.port : json.port,
Password = server.password ?? json.password,
EncryptMethod = server.encryption ?? json.encryption,
Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin,
PluginOption = string.IsNullOrEmpty(json.plugin_options)
? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options
: json.plugin_options
})
})
.Where(CheckServer);
}

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Models;
using Netch.Models;
using System.Collections.Generic;
namespace Netch.Servers.Shadowsocks
{

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
namespace Netch.Servers.ShadowsocksR
@@ -8,9 +9,9 @@ namespace Netch.Servers.ShadowsocksR
{
public override string MainFile { get; protected set; } = "ShadowsocksR.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"listening at"};
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "listening at" };
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"Invalid config path", "usage"};
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "Invalid config path", "usage" };
public override string Name { get; } = "ShadowsocksR";
@@ -20,7 +21,7 @@ namespace Netch.Servers.ShadowsocksR
public void Start(in Server s, in Mode mode)
{
var server = (ShadowsocksR) s;
var server = (ShadowsocksR)s;
var command = new SSRParameter
{

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.ShadowsocksR.Form;
@@ -19,13 +19,13 @@ namespace Netch.Servers.ShadowsocksR
public string ShortName { get; } = "SR";
public string[] UriScheme { get; } = {"ssr"};
public string[] UriScheme { get; } = { "ssr" };
public Type ServerType { get; } = typeof(ShadowsocksR);
public void Edit(Server s)
{
new ShadowsocksRForm((ShadowsocksR) s).ShowDialog();
new ShadowsocksRForm((ShadowsocksR)s).ShowDialog();
}
public void Create()
@@ -35,7 +35,7 @@ namespace Netch.Servers.ShadowsocksR
public string GetShareLink(Server s)
{
var server = (ShadowsocksR) s;
var server = (ShadowsocksR)s;
// https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
// ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
@@ -143,7 +143,7 @@ namespace Netch.Servers.ShadowsocksR
public bool CheckServer(Server s)
{
var server = (ShadowsocksR) s;
var server = (ShadowsocksR)s;
if (!SSRGlobal.EncryptMethods.Contains(server.EncryptMethod))
{
Global.Logger.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}");

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Models;
using Netch.Models;
using System.Collections.Generic;
namespace Netch.Servers.ShadowsocksR
{

View File

@@ -9,7 +9,7 @@ namespace Netch.Servers.Socks5
public override void Start(in Server s, in Mode mode)
{
var server = (Socks5) s;
var server = (Socks5)s;
if (server.Auth())
base.Start(s, mode);
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Socks5.Form;
@@ -23,7 +23,7 @@ namespace Netch.Servers.Socks5
public void Edit(Server s)
{
new Socks5Form((Socks5) s).ShowDialog();
new Socks5Form((Socks5)s).ShowDialog();
}
public void Create()
@@ -33,7 +33,7 @@ namespace Netch.Servers.Socks5
public string GetShareLink(Server s)
{
var server = (Socks5) s;
var server = (Socks5)s;
// https://t.me/socks?server=1.1.1.1&port=443
return $"https://t.me/socks?server={server.Hostname}&port={server.Port}" +
$"{(!string.IsNullOrWhiteSpace(server.Username) ? $"&user={server.Username}" : "")}" +
@@ -68,7 +68,7 @@ namespace Netch.Servers.Socks5
if (dict.ContainsKey("pass") && !string.IsNullOrWhiteSpace(dict["pass"]))
data.Password = dict["pass"];
return new[] {data};
return new[] { data };
}
public bool CheckServer(Server s)

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Text.Json;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Trojan.Models;
@@ -11,9 +12,9 @@ namespace Netch.Servers.Trojan
{
public override string MainFile { get; protected set; } = "Trojan.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"started"};
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "started" };
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"exiting"};
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "exiting" };
public override string Name { get; } = "Trojan";
@@ -23,7 +24,7 @@ namespace Netch.Servers.Trojan
public void Start(in Server s, in Mode mode)
{
var server = (Trojan) s;
var server = (Trojan)s;
var trojanConfig = new TrojanConfig
{
local_addr = this.LocalAddress(),

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Trojan.Form;
@@ -18,13 +18,13 @@ namespace Netch.Servers.Trojan
public string ShortName { get; } = "TR";
public string[] UriScheme { get; } = {"trojan"};
public string[] UriScheme { get; } = { "trojan" };
public Type ServerType { get; } = typeof(Trojan);
public void Edit(Server s)
{
new TrojanForm((Trojan) s).ShowDialog();
new TrojanForm((Trojan)s).ShowDialog();
}
public void Create()
@@ -34,7 +34,7 @@ namespace Netch.Servers.Trojan
public string GetShareLink(Server s)
{
var server = (Trojan) s;
var server = (Trojan)s;
return $"trojan://{HttpUtility.UrlEncode(server.Password)}@{server.Hostname}:{server.Port}#{server.Remark}";
}
@@ -79,7 +79,7 @@ namespace Netch.Servers.Trojan
data.Hostname = match.Groups["server"].Value;
data.Port = ushort.Parse(match.Groups["port"].Value);
return new[] {data};
return new[] { data };
}
public bool CheckServer(Server s)

View File

@@ -1,8 +1,9 @@
using System.Collections.Generic;
using Netch.Models;
using Netch.Servers.V2ray.Models;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Netch.Models;
using Netch.Servers.V2ray.Models;
using Netch.Enums;
using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig;
namespace Netch.Servers.V2ray.Utils
@@ -65,7 +66,7 @@ namespace Netch.Servers.V2ray.Utils
outboundTag = "block"
};
if (mode.Type is 0 or 1 or 2)
if (mode.Type is ModeType.Process or ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs)
blockRuleObject.ip.Add("geoip:private");
static bool CheckRuleItem(ref RulesItem rulesItem)
@@ -109,8 +110,8 @@ namespace Netch.Servers.V2ray.Utils
switch (server)
{
case Socks5.Socks5 socks5:
{
outbound.settings.servers = new List<ServersItem>
{
outbound.settings.servers = new List<ServersItem>
{
new()
{
@@ -130,80 +131,80 @@ namespace Netch.Servers.V2ray.Utils
}
};
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
outbound.protocol = "socks";
break;
}
case VLESS.VLESS vless:
{
var vnextItem = new VnextItem
{
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.settings.vnext = new List<VnextItem> {vnextItem};
var usersItem = new UsersItem
{
id = vless.UserID,
alterId = 0,
flow = string.Empty,
encryption = vless.EncryptMethod
};
vnextItem.users.Add(usersItem);
var streamSettings = outbound.streamSettings;
boundStreamSettings(vless, ref streamSettings);
if (vless.TLSSecureType == "xtls")
{
usersItem.flow = string.IsNullOrEmpty(vless.Flow) ? "xtls-rprx-origin" : vless.Flow;
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
outbound.protocol = "socks";
break;
}
else
case VLESS.VLESS vless:
{
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
}
var vnextItem = new VnextItem
{
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.protocol = "vless";
outbound.settings.servers = null;
break;
}
outbound.settings.vnext = new List<VnextItem> { vnextItem };
var usersItem = new UsersItem
{
id = vless.UserID,
alterId = 0,
flow = string.Empty,
encryption = vless.EncryptMethod
};
vnextItem.users.Add(usersItem);
var streamSettings = outbound.streamSettings;
boundStreamSettings(vless, ref streamSettings);
if (vless.TLSSecureType == "xtls")
{
usersItem.flow = string.IsNullOrEmpty(vless.Flow) ? "xtls-rprx-origin" : vless.Flow;
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
}
else
{
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
}
outbound.protocol = "vless";
outbound.settings.servers = null;
break;
}
case VMess.VMess vmess:
{
var vnextItem = new VnextItem
{
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
var vnextItem = new VnextItem
{
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.settings.vnext = new List<VnextItem> {vnextItem};
outbound.settings.vnext = new List<VnextItem> { vnextItem };
var usersItem = new UsersItem
{
id = vmess.UserID,
alterId = vmess.AlterID,
security = vmess.EncryptMethod
};
var usersItem = new UsersItem
{
id = vmess.UserID,
alterId = vmess.AlterID,
security = vmess.EncryptMethod
};
vnextItem.users.Add(usersItem);
vnextItem.users.Add(usersItem);
var streamSettings = outbound.streamSettings;
boundStreamSettings(vmess, ref streamSettings);
var streamSettings = outbound.streamSettings;
boundStreamSettings(vmess, ref streamSettings);
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
outbound.protocol = "vmess";
break;
}
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
outbound.protocol = "vmess";
break;
}
}
v2rayConfig.outbounds.AddRange(new[]
@@ -274,7 +275,7 @@ namespace Netch.Servers.V2ray.Utils
case "ws":
var wsSettings = new WsSettings
{
headers = !string.IsNullOrWhiteSpace(server.Host) ? new Headers {Host = server.Host} : null,
headers = !string.IsNullOrWhiteSpace(server.Host) ? new Headers { Host = server.Host } : null,
path = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
};

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.V2ray.Utils;
@@ -10,9 +11,9 @@ namespace Netch.Servers.V2ray
{
public override string MainFile { get; protected set; } = "xray.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"started"};
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] { "started" };
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"config file not readable", "failed to"};
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] { "config file not readable", "failed to" };
public override string Name { get; } = "Xray";

View File

@@ -1,10 +1,10 @@
using Netch.Models;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using Netch.Models;
using Netch.Utils;
namespace Netch.Servers.V2ray
{
@@ -13,7 +13,7 @@ namespace Netch.Servers.V2ray
public static IEnumerable<Server> ParseVUri(string text)
{
var scheme = ShareLink.GetUriScheme(text).ToLower();
var server = scheme switch {"vmess" => new VMess.VMess(), "vless" => new VLESS.VLESS(), _ => throw new ArgumentOutOfRangeException()};
var server = scheme switch { "vmess" => new VMess.VMess(), "vless" => new VLESS.VLESS(), _ => throw new ArgumentOutOfRangeException() };
if (text.Contains("#"))
{
server.Remark = Uri.UnescapeDataString(text.Split('#')[1]);
@@ -25,7 +25,7 @@ namespace Netch.Servers.V2ray
var parameter = HttpUtility.ParseQueryString(text.Split('?')[1]);
text = text.Substring(0, text.IndexOf("?", StringComparison.Ordinal));
server.TransferProtocol = parameter.Get("type") ?? "tcp";
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch {"vless" => "none", _ => "auto"};
server.EncryptMethod = parameter.Get("encryption") ?? scheme switch { "vless" => "none", _ => "auto" };
switch (server.TransferProtocol)
{
case "tcp":
@@ -54,7 +54,7 @@ namespace Netch.Servers.V2ray
{
server.Host = parameter.Get("sni") ?? "";
if (server.TLSSecureType == "xtls")
((VLESS.VLESS) server).Flow = parameter.Get("flow") ?? "";
((VLESS.VLESS)server).Flow = parameter.Get("flow") ?? "";
}
}
@@ -67,13 +67,13 @@ namespace Netch.Servers.V2ray
server.Hostname = match.Groups["server"].Value;
server.Port = ushort.Parse(match.Groups["port"].Value);
return new[] {server};
return new[] { server };
}
public static string GetVShareLink(Server s, string scheme = "vmess")
{
// https://github.com/XTLS/Xray-core/issues/91
var server = (VMess.VMess) s;
var server = (VMess.VMess)s;
var parameter = new Dictionary<string, string>();
// protocol-specific fields
parameter.Add("type", server.TransferProtocol);
@@ -127,7 +127,7 @@ namespace Netch.Servers.V2ray
if (server.TLSSecureType == "xtls")
{
var flow = ((VLESS.VLESS) server).Flow;
var flow = ((VLESS.VLESS)server).Flow;
if (!flow.IsNullOrWhiteSpace())
parameter.Add("flow", flow!.Replace("-udp443", ""));
}

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Servers.VMess;
using System.Collections.Generic;
namespace Netch.Servers.VLESS
{

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Forms;
using System.Collections.Generic;
namespace Netch.Servers.VLESS.VLESSForm
{
@@ -30,8 +30,8 @@ namespace Netch.Servers.VLESS.VLESSForm
CreateTextBox("QUICSecret", "QUIC Secret", s => true, s => server.QUICSecret = s, server.QUICSecret);
CreateComboBox("UseMux",
"Use Mux",
new List<string> {"", "true", "false"},
s => server.UseMux = s switch {"" => null, "true" => true, "false" => false, _ => null},
new List<string> { "", "true", "false" },
s => server.UseMux = s switch { "" => null, "true" => true, "false" => false, _ => null },
server.UseMux?.ToString().ToLower() ?? "");
CreateComboBox("TLSSecure", "TLS Secure", VLESSGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.V2ray;
@@ -16,13 +16,13 @@ namespace Netch.Servers.VLESS
public string ShortName { get; } = "VL";
public string[] UriScheme { get; } = {"vless"};
public string[] UriScheme { get; } = { "vless" };
public Type ServerType { get; } = typeof(VLESS);
public void Edit(Server s)
{
new VLESSForm.VLESSForm((VLESS) s).ShowDialog();
new VLESSForm.VLESSForm((VLESS)s).ShowDialog();
}
public void Create()

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Forms;
using Netch.Forms;
using System.Collections.Generic;
namespace Netch.Servers.VMess.Form
{
@@ -25,8 +25,8 @@ namespace Netch.Servers.VMess.Form
CreateTextBox("QUICSecret", "QUIC Secret", s => true, s => server.QUICSecret = s, server.QUICSecret);
CreateComboBox("UseMux",
"Use Mux",
new List<string> {"", "true", "false"},
s => server.UseMux = s switch {"" => null, "true" => true, "false" => false, _ => null},
new List<string> { "", "true", "false" },
s => server.UseMux = s switch { "" => null, "true" => true, "false" => false, _ => null },
server.UseMux?.ToString().ToLower() ?? "");
CreateComboBox("TLSSecure", "TLS Secure", VMessGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Netch.Models;
using System.Collections.Generic;
namespace Netch.Servers.VMess
{

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.V2ray;
using Netch.Servers.V2ray.Models;
@@ -22,13 +22,13 @@ namespace Netch.Servers.VMess
public string ShortName { get; } = "V2";
public string[] UriScheme { get; } = {"vmess"};
public string[] UriScheme { get; } = { "vmess" };
public Type ServerType { get; } = typeof(VMess);
public void Edit(Server s)
{
new VMessForm((VMess) s).ShowDialog();
new VMessForm((VMess)s).ShowDialog();
}
public void Create()
@@ -40,22 +40,22 @@ namespace Netch.Servers.VMess
{
if (Global.Settings.V2RayConfig.V2rayNShareLink)
{
var server = (VMess) s;
var server = (VMess)s;
var vmessJson = JsonSerializer.Serialize(new V2rayNSharing
{
v = 2,
ps = server.Remark,
add = server.Hostname,
port = server.Port,
id = server.UserID,
aid = server.AlterID,
net = server.TransferProtocol,
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecureType
},
{
v = 2,
ps = server.Remark,
add = server.Hostname,
port = server.Port,
id = server.UserID,
aid = server.AlterID,
net = server.TransferProtocol,
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecureType
},
new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
@@ -87,7 +87,7 @@ namespace Netch.Servers.VMess
}
V2rayNSharing vmess = JsonSerializer.Deserialize<V2rayNSharing>(s,
new JsonSerializerOptions {NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString})!;
new JsonSerializerOptions { NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString })!;
data.Remark = vmess.ps;
data.Hostname = vmess.add;
@@ -114,7 +114,7 @@ namespace Netch.Servers.VMess
data.TLSSecureType = vmess.tls;
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
return new[] {data};
return new[] { data };
}
public bool CheckServer(Server s)

View File

@@ -1,3 +1,7 @@
using Netch.Controllers;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -6,10 +10,6 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using Netch.Controllers;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Updater
{
@@ -92,7 +92,7 @@ namespace Netch.Updater
#region Apply Update
private static readonly ImmutableArray<string> KeepDirectories = new List<string> {"data", "mode\\Custom", "logging"}.ToImmutableArray();
private static readonly ImmutableArray<string> KeepDirectories = new List<string> { "data", "mode\\Custom", "logging" }.ToImmutableArray();
private void ApplyUpdate()
{

View File

@@ -1,11 +1,11 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
using Netch.Controllers;
using Netch.Models;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace Netch.Utils
{
@@ -14,7 +14,7 @@ namespace Netch.Utils
public static ulong received;
public static TraceEventSession? tSession;
private static readonly string[] Suffix = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
private static readonly string[] Suffix = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };
/// <summary>
/// 计算流量
@@ -98,7 +98,7 @@ namespace Netch.Utils
{
if (processList.Contains(data.ProcessID))
lock (counterLock)
received += (ulong) data.size;
received += (ulong)data.size;
// Debug.WriteLine($"TcpIpRecv: {ToByteSize(data.size)}");
};
@@ -107,7 +107,7 @@ namespace Netch.Utils
{
if (processList.Contains(data.ProcessID))
lock (counterLock)
received += (ulong) data.size;
received += (ulong)data.size;
// Debug.WriteLine($"UdpIpRecv: {ToByteSize(data.size)}");
};

View File

@@ -1,9 +1,9 @@
using System;
using Netch.Models;
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Netch.Models;
namespace Netch.Utils
{
@@ -75,7 +75,8 @@ namespace Netch.Utils
if (!Directory.Exists(DataDirectoryFullName))
Directory.CreateDirectory(DataDirectoryFullName);
File.WriteAllBytes(SettingFileFullName, JsonSerializer.SerializeToUtf8Bytes(Global.Settings, JsonSerializerOptions));
using var fileStream = File.Create(SettingFileFullName);
JsonSerializer.SerializeAsync(fileStream, Global.Settings, JsonSerializerOptions).Wait();
}
}
}

View File

@@ -2,6 +2,8 @@ using System;
using System.IO;
using System.Linq;
using Netch.Controllers;
using Netch.Enums;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
@@ -111,35 +113,33 @@ namespace Netch.Utils
{
switch (mode.Type)
{
case 0:
case ModeType.Process:
return server switch
{
Socks5 => true,
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS => true,
_ => false
};
case 1:
case 2:
{
Socks5 => true,
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS => true,
_ => false
};
case ModeType.ProxyRuleIPs:
case ModeType.BypassRuleIPs:
return server is Socks5;
default:
return false;
}
}
public static readonly int[] ModeTypes = {0, 1, 2, 6};
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName)
public static IModeController GetModeControllerByType(ModeType type, out ushort? port, out string portName)
{
port = null;
portName = string.Empty;
switch (type)
{
case 0:
case ModeType.Process:
return new NFController();
case 1:
case 2:
case ModeType.ProxyRuleIPs:
case ModeType.BypassRuleIPs:
return new TUNController();
case 6:
case ModeType.Pcap2Socks:
return new PcapController();
default:
Global.Logger.Error("未知模式类型");

View File

@@ -0,0 +1,96 @@
using System;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using Netch.Models;
using Vanara.PInvoke;
namespace Netch.Utils
{
public static class NetworkInterfaceUtils
{
public static NetworkInterface GetBest(AddressFamily addressFamily = AddressFamily.InterNetwork)
{
var ipAddress = addressFamily switch
{
AddressFamily.InterNetwork => "114.114.114.114",
AddressFamily.InterNetworkV6 => throw new NotImplementedException(),
_ => throw new ArgumentOutOfRangeException(nameof(addressFamily), addressFamily, null)
};
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0), 0, out var route) != 0)
throw new MessageException("GetBestRoute 搜索失败");
return Get((int)route.dwForwardIfIndex);
}
/// <summary>
/// </summary>
/// <param name="interfaceIndex"></param>
/// <exception cref="InvalidOperationException"></exception>
/// <returns></returns>
public static NetworkInterface Get(int interfaceIndex)
{
return NetworkInterface.GetAllNetworkInterfaces().First(n => n.GetIndex() == interfaceIndex);
}
public static NetworkInterface Get(string description)
{
return NetworkInterface.GetAllNetworkInterfaces().First(n => n.Description == description);
}
public static void SetInterfaceMetric(int interfaceIndex, int? metric = null)
{
var arguments = $"interface ip set interface {interfaceIndex} ";
if (metric != null)
arguments += $"metric={metric} ";
Utils.ProcessRunHiddenAsync("netsh", arguments).Wait();
}
}
public static class NetworkInterfaceExtension
{
public static int GetIndex(this NetworkInterface ni)
{
var ipProperties = ni.GetIPProperties();
if (ni.Supports(NetworkInterfaceComponent.IPv4))
return ipProperties.GetIPv4Properties().Index;
if (ni.Supports(NetworkInterfaceComponent.IPv6))
return ipProperties.GetIPv6Properties().Index;
throw new Exception();
}
public static void SetDns(this NetworkInterface ni, string primaryDns, string? secondDns = null)
{
void VerifyDns(ref string s)
{
s = s.Trim();
if (primaryDns.IsNullOrEmpty())
throw new ArgumentException("DNS format invalid", nameof(primaryDns));
}
VerifyDns(ref primaryDns);
if (secondDns != null)
VerifyDns(ref primaryDns);
var wmi = new ManagementClass("Win32_NetworkAdapterConfiguration");
var mos = wmi.GetInstances().Cast<ManagementObject>();
var mo = mos.First(m => m["Description"].ToString() == ni.Description);
var dns = new[] { primaryDns };
if (secondDns != null)
dns = dns.Append(secondDns).ToArray();
var inPar = mo.GetMethodParameters("SetDNSServerSearchOrder");
inPar["DNSServerSearchOrder"] = dns;
mo.InvokeMethod("SetDNSServerSearchOrder", inPar, null);
}
}
}

View File

@@ -3,16 +3,16 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using Netch.Models;
using static Vanara.PInvoke.IpHlpApi;
using static Vanara.PInvoke.Ws2_32;
using Range = Netch.Models.Range;
namespace Netch.Utils
{
public static class PortHelper
{
private static readonly List<Range> TCPReservedRanges = new();
private static readonly List<Range> UDPReservedRanges = new();
private static readonly List<NumberRange> TCPReservedRanges = new();
private static readonly List<NumberRange> UDPReservedRanges = new();
private static readonly IPGlobalProperties NetInfo = IPGlobalProperties.GetIPGlobalProperties();
static PortHelper()
@@ -33,12 +33,12 @@ namespace Netch.Utils
if (port == 0)
throw new ArgumentOutOfRangeException();
var row = GetTcpTable2().Where(r => ntohs((ushort) r.dwLocalPort) == port).Where(r => r.dwOwningPid is not (0 or 4));
var row = GetTcpTable2().Where(r => ntohs((ushort)r.dwLocalPort) == port).Where(r => r.dwOwningPid is not (0 or 4));
return row.Select(r => Process.GetProcessById((int) r.dwOwningPid));
return row.Select(r => Process.GetProcessById((int)r.dwOwningPid));
}
private static void GetReservedPortRange(PortType portType, ref List<Range> targetList)
private static void GetReservedPortRange(PortType portType, ref List<NumberRange> targetList)
{
var process = new Process
{
@@ -64,7 +64,7 @@ namespace Netch.Utils
if (!ushort.TryParse(value[0], out var start) || !ushort.TryParse(value[1], out var end))
continue;
targetList.Add(new Range(start, end));
targetList.Add(new NumberRange(start, end));
}
}
@@ -143,7 +143,7 @@ namespace Netch.Utils
var random = new Random();
for (ushort i = 0; i < 55535; i++)
{
var p = (ushort) random.Next(10000, 65535);
var p = (ushort)random.Next(10000, 65535);
try
{
CheckPort(p, portType);

69
Netch/Utils/RouteUtils.cs Normal file
View File

@@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net.Sockets;
using Netch.Interops;
using Netch.Models;
namespace Netch.Utils
{
public static class RouteUtils
{
public static void CreateRouteFill(NetRoute template, IEnumerable<string> rules, int? metric = null)
{
foreach (var rule in rules)
CreateRouteFill(template, rule, metric);
}
public static bool CreateRouteFill(NetRoute template, string rule, int? metric = null)
{
if (!TryParseIPNetwork(rule, out var network, out var cidr))
{
Global.Logger.Warning($"invalid rule {rule}");
return false;
}
return CreateRoute(template.FillTemplate(network, (byte)cidr, metric));
}
public static bool CreateRoute(NetRoute o)
{
return RouteHelper.CreateRoute(AddressFamily.InterNetwork, o.Network, o.Cidr, o.Gateway, (ulong)o.InterfaceIndex, o.Metric);
}
public static void DeleteRouteFill(NetRoute template, IEnumerable<string> rules, int? metric = null)
{
foreach (var rule in rules)
DeleteRouteFill(template, rule, metric);
}
public static bool DeleteRouteFill(NetRoute template, string rule, int? metric = null)
{
if (!TryParseIPNetwork(rule, out var network, out var cidr))
{
Global.Logger.Warning($"invalid rule {rule}");
return false;
}
return DeleteRoute(template.FillTemplate(network, (byte)cidr, metric));
}
public static bool DeleteRoute(NetRoute o)
{
return RouteHelper.DeleteRoute(AddressFamily.InterNetwork, o.Network, o.Cidr, o.Gateway, (ulong)o.InterfaceIndex, o.Metric);
}
public static bool TryParseIPNetwork(string ipNetwork, [NotNullWhen(true)] out string? ip, out int cidr)
{
ip = null;
cidr = 0;
var s = ipNetwork.Split('/');
if (s.Length != 2)
return false;
ip = s[0];
cidr = int.Parse(s[1]);
return true;
}
}
}

View File

@@ -1,7 +1,7 @@
using System;
using Netch.Models;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Netch.Models;
namespace Netch.Utils
{
@@ -16,7 +16,7 @@ namespace Netch.Utils
try
{
var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!);
return (Server) JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
}
catch
{

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Timers;
using Netch.Interfaces;
using Netch.Models;
using Range = Netch.Models.Range;
namespace Netch.Utils
{
@@ -17,7 +17,7 @@ namespace Netch.Utils
.GetExportedTypes()
.Where(type => type.GetInterfaces().Contains(typeof(IServerUtil)));
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil) Activator.CreateInstance(t)!).OrderBy(util => util.Priority);
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).OrderBy(util => util.Priority);
}
public static Type GetTypeByTypeName(string typeName)
@@ -32,7 +32,7 @@ namespace Netch.Utils
private static readonly Timer Timer;
private static bool _mux;
public static readonly Range Range = new(0, int.MaxValue / 1000);
public static readonly NumberRange Range = new(0, int.MaxValue / 1000);
static DelayTestHelper()
{
@@ -57,7 +57,7 @@ namespace Netch.Utils
}
}
public static int Interval => (int) (Timer.Interval / 1000);
public static int Interval => (int)(Timer.Interval / 1000);
private static bool ValueIsEnabled(int value)
{
@@ -74,7 +74,7 @@ namespace Netch.Utils
try
{
_mux = true;
Parallel.ForEach(Global.Settings.Server, new ParallelOptions {MaxDegreeOfParallelism = 16}, server => { server.Test(); });
Parallel.ForEach(Global.Settings.Server, new ParallelOptions { MaxDegreeOfParallelism = 16 }, server => { server.Test(); });
_mux = false;
TestDelayFinished?.Invoke(null, new EventArgs());
}

View File

@@ -1,12 +1,12 @@
using System;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Shadowsocks.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Shadowsocks.Models;
namespace Netch.Utils
{
@@ -122,7 +122,7 @@ namespace Netch.Utils
return JsonSerializer.Deserialize<Server>(text,
new JsonSerializerOptions
{
Converters = {new ServerConverterWithTypeDiscriminator()}
Converters = { new ServerConverterWithTypeDiscriminator() }
})!;
}
@@ -158,7 +158,7 @@ namespace Netch.Utils
private static string RemoveEmoji(string text)
{
byte[] emojiBytes = {240, 159};
byte[] emojiBytes = { 240, 159 };
var remark = Encoding.UTF8.GetBytes(text);
var startIndex = 0;
while (remark.Length > startIndex + 1 && remark[startIndex] == emojiBytes[0] && remark[startIndex + 1] == emojiBytes[1])

View File

@@ -48,7 +48,7 @@ namespace Netch.Utils
var sb = new StringBuilder();
foreach (var t in value)
{
var escapeCharacters = new[] {'\\', '*', '+', '?', '|', '{', '}', '[', ']', '(', ')', '^', '$', '.'};
var escapeCharacters = new[] { '\\', '*', '+', '?', '|', '{', '}', '[', ']', '(', ')', '^', '$', '.' };
if (escapeCharacters.Any(s => s == t))
sb.Append('\\');

View File

@@ -1,9 +1,9 @@
using Netch.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Netch.Models;
namespace Netch.Utils
{

View File

@@ -219,8 +219,8 @@ namespace Netch.Utils
{
case TextBox _:
case ComboBox _:
if (((Control) component).ForeColor != color)
((Control) component).ForeColor = color;
if (((Control)component).ForeColor != color)
((Control)component).ForeColor = color;
break;
}
@@ -254,7 +254,7 @@ namespace Netch.Utils
Console.Write(error);
}
p.WaitForExit();
await p.WaitForExitAsync();
}
public static int SubnetToCidr(string value)
@@ -275,5 +275,15 @@ namespace Netch.Utils
return host;
}
public static string GetHostFromUri(string str)
{
var startIndex = str.LastIndexOf('/');
if (startIndex != -1)
str = str[(startIndex + 1)..];
var endIndex = str.IndexOf(':');
return endIndex == -1 ? str : str[..endIndex];
}
}
}

View File

@@ -19,7 +19,7 @@ namespace Netch.Utils
public static HttpWebRequest CreateRequest(string url, int? timeout = null, string? userAgent = null)
{
var req = (HttpWebRequest) WebRequest.Create(url);
var req = (HttpWebRequest)WebRequest.Create(url);
req.UserAgent = string.IsNullOrWhiteSpace(userAgent) ? DefaultUserAgent : userAgent;
req.Accept = "*/*";
req.KeepAlive = true;
@@ -53,7 +53,7 @@ namespace Netch.Utils
/// <returns></returns>
public static string DownloadString(HttpWebRequest req, out HttpWebResponse rep, string encoding = "UTF-8")
{
rep = (HttpWebResponse) req.GetResponse();
rep = (HttpWebResponse)req.GetResponse();
using var responseStream = rep.GetResponseStream();
using var streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encoding));
@@ -83,7 +83,7 @@ namespace Netch.Utils
/// <returns></returns>
public static async Task DownloadFileAsync(HttpWebRequest req, string fileFullPath)
{
using var webResponse = (HttpWebResponse) await req.GetResponseAsync();
using var webResponse = (HttpWebResponse)await req.GetResponseAsync();
await using var input = webResponse.GetResponseStream();
await using var fileStream = File.OpenWrite(fileFullPath);

View File

@@ -1,4 +1,5 @@
using System.Collections;
using Netch.Properties;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -6,7 +7,6 @@ using System.Linq;
using System.Text;
using System.Text.Json;
using System.Windows.Forms;
using Netch.Properties;
namespace Netch.Utils
{
@@ -99,14 +99,14 @@ namespace Netch.Utils
{
for (var i = 0; i < args.Length; i++)
if (args[i] is string)
args[i] = Translate((string) args[i]);
args[i] = Translate((string)args[i]);
return string.Format(Translate(format), args);
}
public static List<string> GetTranslateList()
{
var translateFile = new List<string> {"System", "zh-CN", "en-US"};
var translateFile = new List<string> { "System", "zh-CN", "en-US" };
if (!Directory.Exists("i18n"))
return translateFile;

View File

@@ -1,70 +1,57 @@
<p align="center"><img src="https://github.com/NetchX/Netch/blob/master/Netch/Resources/Netch.png?raw=true" width="128" /></p>
<div align="center">
# Netch
[![Group](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/Netch_Discuss_Group)
[![Channel](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/Netch)
[![Platform](https://img.shields.io/badge/platform-windows-orange.svg)](https://github.com/NetchX/Netch)
[![Version](https://img.shields.io/github/v/release/NetchX/Netch)](https://github.com/NetchX/Netch/releases)
[![Downloads](https://img.shields.io/github/downloads/NetchX/Netch/total.svg)](https://github.com/NetchX/Netch/releases)
[![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)](https://github.com/NetchX/Netch/actions)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
A simple proxy client like SSTap
[文档网站](https://netch.org/) [常见问题](https://netch.org/#/docs/zh-CN/faq)
[![](https://img.shields.io/badge/telegram-group-green?style=flat-square)](https://t.me/netch_group)
[![](https://img.shields.io/badge/telegram-channel-blue?style=flat-square)](https://t.me/netch_channel)
[![](https://img.shields.io/github/downloads/NetchX/Netch/total.svg?style=flat-square)](https://github.com/NetchX/Netch/releases)
[![](https://img.shields.io/github/v/release/NetchX/Netch?style=flat-square)](https://github.com/NetchX/Netch/releases)
</div>
[中文说明](README.zh-CN.md)
## Features
Some features may not be implemented in version 1.0
Game network accelerator
### Modes
- ProcessMode - Use Netfilter driver to intercept process traffic
- ShareMode - Share your network based on WinPcap / Npcap
- TapMode - Use TAP-Windows driver to create virtual adapter
- TunMode - Use WinTUN driver to create virtual adapter
- WebMode - Web proxy mode
- WmpMode - Proxy forwarding (eg. OBS Streaming)
## TOC
- [Netch](#netch)
- [TOC](#toc)
- [Description](#description)
- [Sponsor](#sponsor)
- [Donate](#donate)
- [Screenshots](#screenshots)
- [Requirements](#requirements)
- [Quote](#quote)
### Protocols
- [Socks5](https://www.wikiwand.com/en/SOCKS)
- [Shadowsocks](https://github.com/shadowsocks/shadowsocks-libev)
- [ShadowsocksR](https://github.com/shadowsocksrr/shadowsocksr-libev)
- [Trojan](https://trojan-gfw.github.io/trojan/)
- [VMess](https://github.com/v2fly/v2ray-core)
- [VLess](https://github.com/xtls/xray-core)
## Description
Netch is an open source game network accelerator. Unlike SSTap, which needs to add rules to function as a blacklist proxy, Netch is more similar to SocksCap64, which can scan the game directory to get their process names specifically and forward their network traffic through the proxy server
Currently supports the following protocols
- Socks5
- Shadowsocks
- ShadowsocksR
- Trojan
- VMess
- VLESS
As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an NATTypeTester to test out what your NAT type is. When using SSTap to speed up some P2P gaming connections or the game is required for that kind of open NAT type, you may experience some bad situations such as unable to join the game
### Others
- UDP NAT FullCone (May limited by your server)
- .NET 5.0
## Sponsor
<a href="https://www.jetbrains.com/?from=Netch"><img src="jetbrains.svg" alt="JetBrains" width="200"/></a>
- [RabbitHosts](https://rabbithosts.com/cart.php)
- [ManSora](https://www.mansora.co/cart.php)
- [NyanCat](https://nyancat.info/register)
- [NeroCloud](https://nerocloud.io)
## Donate
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
- ETH *0x23dac0a93bcd71fec7a95833ad030338f167f185*
## Screenshots
![](images/screenshots/main.png)
## Credit
- [WinTUN](https://www.wintun.net)
- [NetFilter](https://netfiltersdk.com)
- [aioCloud](https://github.com/aiocloud)
- [Shadowsocks](https://github.com/shadowsocks/shadowsocks-libev)
- [ShadowsocksR](https://github.com/shadowsocksrr/shadowsocksr-libev)
- [Trojan](https://github.com/trojan-gfw/trojan)
- [V2Ray](https://github.com/v2fly/v2ray-core)
- [XRay](https://github.com/xtls/xray-core)
## Requirements
- [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0/runtime)
## Quote
- [core](https://github.com/aiocloud/core)
- [aiodns](https://github.com/aiocloud/aiodns)
- [tun2socks](https://github.com/aiocloud/tun2socks)
- [Redirector](https://github.com/aiocloud/Redirector)
- [RouteHelper](https://github.com/aiocloud/RouteHelper)
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
- [NetFilter SDK](https://netfiltersdk.com)
- [pcap2socks](https://github.com/zhxie/pcap2socks)
- [shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev)
- [shadowsocksr-libev](https://github.com/shadowsocksrr/shadowsocksr-libev)
- [trojan](https://github.com/trojan-gfw/trojan)
- [xray-core](https://github.com/XTLS/Xray-core)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
[![Stargazers over time](https://starchart.cc/NetchX/Netch.svg)](https://starchart.cc/NetchX/Netch)
## Stars
[![](https://starchart.cc/NetchX/Netch.svg)](https://starchart.cc/NetchX/Netch)

View File

@@ -1,70 +0,0 @@
# Netch
[![群组](https://img.shields.io/badge/Telegram-群组-green)](https://t.me/Netch_Discuss_Group)
[![频道](https://img.shields.io/badge/Telegram-频道-blue)](https://t.me/Netch)
[![平台](https://img.shields.io/badge/平台-windows-orange.svg)](https://github.com/NetchX/Netch)
[![版本](https://img.shields.io/github/v/release/NetchX/Netch)](https://github.com/NetchX/Netch/releases)
[![下载](https://img.shields.io/github/downloads/NetchX/Netch/total.svg)](https://github.com/NetchX/Netch/releases)
[![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)](https://github.com/NetchX/Netch/actions)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
[文档网站](https://netch.org/) [常见问题](https://netch.org/#/docs/zh-CN/faq)
游戏加速工具
## TOC
- [Netch](#netch)
- [TOC](#toc)
- [简介](#简介)
- [赞助商](#赞助商)
- [捐赠](#捐赠)
- [依赖](#依赖)
- [语言支持](#语言支持)
- [引用](#引用)
## 简介
Netch 是一款 Windows 平台的开源游戏加速工具Netch 可以实现类似 SocksCap64 那样的进程代理,也可以实现 SSTap 那样的全局 TUN/TAP 代理,和 Shadowsocks-Windows 那样的本地 Socks5HTTP 和系统代理
至于连接至远程服务器的代理协议,目前 Netch 支持以下代理协议
- Socks5
- Shadowsocks
- ShadowsocksR
- Trojan
- VMess
- VLESS
与此同时 Netch 避免了 SSTap 的 NAT 问题 ,检查 NAT 类型即可知道是否有 NAT 问题。使用 SSTap 加速部分 P2P 联机,对 NAT 类型有要求的游戏时,可能会因为 NAT 类型严格遇到无法加入联机,或者其他影响游戏体验的情况
## 赞助商
<a href="https://www.jetbrains.com/?from=Netch"><img src="jetbrains.svg" alt="JetBrains" width="200"/></a>
- [RabbitHosts](https://rabbithosts.com/cart.php)
- [ManSora](https://www.mansora.co/cart.php)
- [NyanCat](https://nyancat.info/register)
## 捐赠
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
## 依赖
- [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0/runtime)
## 语言支持
Netch 内置 en-US 和 zh-CN外置 zh-TW 等,默认根据系统语言选择语言。
[Netch 外置语言仓库](https://github.com/NetchX/NetchTranslation) ,欢迎提供其他语言的翻译
## 引用
- [core](https://github.com/aiocloud/core)
- [aiodns](https://github.com/aiocloud/aiodns)
- [tun2socks](https://github.com/aiocloud/tun2socks)
- [Redirector](https://github.com/aiocloud/Redirector)
- [RouteHelper](https://github.com/aiocloud/RouteHelper)
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
- [NetFilter SDK](https://netfiltersdk.com)
- [pcap2socks](https://github.com/zhxie/pcap2socks)
- [shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev)
- [shadowsocksr-libev](https://github.com/shadowsocksrr/shadowsocksr-libev)
- [trojan](https://github.com/trojan-gfw/trojan)
- [xray-core](https://github.com/XTLS/Xray-core)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
[![Stargazers over time](https://starchart.cc/NetchX/Netch.svg)](https://starchart.cc/NetchX/Netch)

View File

@@ -22,7 +22,11 @@ param (
$PublishSingleFile = $True
)
.\download.ps1 $OutputPath
.\scripts\download.ps1 $OutputPath
if ( -Not $? ) {
Exit 1
}
Write-Host "Building $Configuration to $OutputPath"
dotnet publish `

View File

@@ -1,36 +1,39 @@
param([string]$OutputPath)
$NetchDataURL="https://github.com/NetchX/NetchData/archive/refs/heads/master.zip"
$NetchModeURL="https://github.com/NetchX/NetchMode/archive/refs/heads/master.zip"
$NetchI18NURL="https://github.com/NetchX/NetchTranslation/archive/refs/heads/master.zip"
$last=$(Get-Location)
New-Item -ItemType Directory -Name $OutputPath | Out-Null
Set-Location $OutputPath
Invoke-WebRequest -Uri $NetchDataURL -OutFile data.zip
Invoke-WebRequest -Uri $NetchModeURL -OutFile mode.zip
Invoke-WebRequest -Uri $NetchI18NURL -OutFile i18n.zip
Expand-Archive -Force -Path data.zip -DestinationPath .
Expand-Archive -Force -Path mode.zip -DestinationPath .
Expand-Archive -Force -Path i18n.zip -DestinationPath .
New-Item -ItemType Directory -Name bin | Out-Null
New-Item -ItemType Directory -Name mode | Out-Null
New-Item -ItemType Directory -Name i18n | Out-Null
Copy-Item -Recurse -Force .\NetchData-master\* .\bin
Copy-Item -Recurse -Force .\NetchMode-master\mode\* .\mode
Copy-Item -Recurse -Force .\NetchTranslation-master\i18n\* .\i18n
Remove-Item -Recurse -Force NetchData-master
Remove-Item -Recurse -Force NetchMode-master
Remove-Item -Recurse -Force NetchTranslation-master
Remove-Item -Force data.zip
Remove-Item -Force mode.zip
Remove-Item -Force i18n.zip
Get-Item *
Set-Location $last
exit 0
param([string]$OutputPath)
$NetchDataURL="https://github.com/NetchX/NetchData/archive/refs/heads/master.zip"
$NetchModeURL="https://github.com/NetchX/NetchMode/archive/refs/heads/master.zip"
$NetchI18NURL="https://github.com/NetchX/NetchI18N/archive/refs/heads/master.zip"
$last=$(Get-Location)
New-Item -ItemType Directory -Name $OutputPath | Out-Null
Set-Location $OutputPath
Invoke-WebRequest -Uri $NetchDataURL -OutFile data.zip
Invoke-WebRequest -Uri $NetchModeURL -OutFile mode.zip
Invoke-WebRequest -Uri $NetchI18NURL -OutFile i18n.zip
Expand-Archive -Force -Path data.zip -DestinationPath .
Expand-Archive -Force -Path mode.zip -DestinationPath .
Expand-Archive -Force -Path i18n.zip -DestinationPath .
New-Item -ItemType Directory -Name bin | Out-Null
New-Item -ItemType Directory -Name mode | Out-Null
New-Item -ItemType Directory -Name i18n | Out-Null
Copy-Item -Recurse -Force .\NetchData-master\* .\bin
Copy-Item -Recurse -Force .\NetchMode-master\mode\* .\mode
Copy-Item -Recurse -Force .\NetchI18N-master\i18n\* .\i18n
Remove-Item -Recurse -Force NetchData-master
Remove-Item -Recurse -Force NetchMode-master
Remove-Item -Recurse -Force NetchI18N-master
Remove-Item -Force data.zip
Remove-Item -Force mode.zip
Remove-Item -Force i18n.zip
..\scripts\download\cloak.ps1 -OutputPath bin
..\scripts\download\xray-core.ps1 -OutputPath bin
Get-Item *
Set-Location $last
exit 0

Some files were not shown because too many files have changed in this diff Show More