Compare commits

...

121 Commits
1.6.4 ... 1.7.0

Author SHA1 Message Date
AmazingDM
ac2e5e943e Update mode 2021-01-04 14:05:15 +08:00
AmazingDM
0957514e05 Bump version to 1.7.0 2021-01-04 14:01:20 +08:00
AmazingDM
35b9f168ff 添加测速方式(TCPing&ICMPing)切换设置选项 2021-01-04 13:59:19 +08:00
AmazingDM
ce15e9468e 不代理TCP流量设置
调整设置界面UI
2021-01-04 13:23:58 +08:00
AmazingDM
4c8508a838 Merge remote-tracking branch 'chsbuffer/fixJob' 2021-01-04 12:45:19 +08:00
ChsBuffer
f931adb005 Fix TrojanController ignores sni (host) value
closes #478, #487
2020-12-31 15:04:53 +08:00
Connection Refused
d4f829d4bd Merge pull request #486 from SekiBetu/dev
set mux to false by default
2020-12-30 09:26:44 +08:00
SekiBetu
51d4ba0fdb set mux to false by default 2020-12-30 06:37:02 +08:00
AmazingDM
ca0870889a 更新NTT,优化部分代码 2020-12-28 15:21:43 +08:00
ChsBuffer
ac3e39e9cd Update AioDNS 2020-12-25 22:44:44 +08:00
ChsBuffer
84765ab96d Delay Add Job 2020-12-25 17:12:03 +08:00
AmazingDM
a18851af15 Update binaries 2020-12-25 13:48:40 +08:00
AmazingDM
42366abcca Update README.md Quote 2020-12-25 13:43:33 +08:00
AmazingDM
cec8358922 PAC 2020-12-25 11:28:38 +08:00
AmazingDM
db8e964351 Update translations 2020-12-25 09:43:48 +08:00
AmazingDM
ad3053298a PAC替换ACL
sysproxy.dll 替换为 nuget WindowsProxy
2020-12-24 22:57:52 +08:00
ChsBuffer
669ca4902f Fix: set encoding only when RedireStd enabled 2020-12-24 16:14:41 +08:00
ChsBuffer
272bf61b0f Remove RedirecStandInput (Fix SS plugin start error) 2020-12-24 15:59:51 +08:00
ChsBuffer
0051e7bb50 Feat ICMPing 2020-12-24 13:32:06 +08:00
ChsBuffer
aa5faa9af6 bump version to 1.6.9 2020-12-22 22:21:23 +08:00
ChsBuffer
a92d1c8244 Update translations 2020-12-22 22:21:09 +08:00
ChsBuffer
6bdcc7ce04 Fix GenerateV2RayConfig 2020-12-22 20:59:29 +08:00
ChsBuffer
b5c7ca4c1a Refactor NFController SetServer 2020-12-22 16:59:32 +08:00
ChsBuffer
7c318a9e49 Remove hardcoded TLS1.3 2020-12-21 11:49:08 +08:00
ChsBuffer
f9724f77c2 Fix mode 1,2 did not ignore BypassChina 2020-12-20 17:34:45 +08:00
ChsBuffer
5d8bbe3518 Bump version to 1.6.8 2020-12-20 16:26:08 +08:00
ChsBuffer
e9f0a5b2f8 Update modes 2020-12-20 16:24:27 +08:00
ChsBuffer
9d086336ea Refactor Mode Load 2020-12-19 18:31:25 +08:00
ChsBuffer
b31bedbc82 Update .editorconfig 2020-12-18 19:33:57 +08:00
ChsBuffer
7f15042c03 Update UpdateChecker 2020-12-18 19:33:57 +08:00
Connection Refused
2c4728f13c Merge pull request #464 from AceDroidX/master
Add NoProxyForUdp
2020-12-18 18:54:34 +08:00
AceDroidX
a2f5c9ab27 Add NoProxyForUdp 2020-12-18 18:14:47 +08:00
ChsBuffer
583bf31c92 Fix #462 2020-12-17 12:39:40 +08:00
ChsBuffer
0275b7718f Update binaries 2020-12-16 23:03:03 +08:00
ChsBuffer
0a226fab22 Fix PictureBox High-DPI scale 2020-12-16 16:57:41 +08:00
ChsBuffer
77680e2c02 Fix attach console 2020-12-16 16:27:40 +08:00
ChsBuffer
2afc5ff21a remove connectionReuse 2020-12-16 12:01:16 +08:00
ChsBuffer
4f4882d7f7 update MainController.StartMode 2020-12-16 11:58:12 +08:00
ChsBuffer
41fdf94a16 remove connectionReuse 2020-12-16 10:50:05 +08:00
ChsBuffer
a3e8826105 feat: Add Redirector SS Setting 2020-12-16 10:25:57 +08:00
ChsBuffer
b7bcb46c78 refactor: NTTController, save NTT log to logging\NTT.log 2020-12-15 21:32:16 +08:00
ChsBuffer
5e27b6a1eb refactor: Remove TUNTAPController savedMode savedServer 2020-12-15 21:08:22 +08:00
ChsBuffer
a5903f5f57 Remove IServerController.Server 2020-12-15 21:07:09 +08:00
ChsBuffer
39eb1b4eef refactor: mode handle supported server 2020-12-15 18:23:40 +08:00
ChsBuffer
23bcac0d5d fix: Shadowsocks.HasPlugin typo 2020-12-15 18:23:19 +08:00
ChsBuffer
38480776f0 Revert "update LangVersion to 9"
This reverts commit e77a40966c.
2020-12-15 17:58:39 +08:00
ChsBuffer
bcccb80ece feat: Redirector Shadowsocks (no plugin) support 2020-12-15 17:31:21 +08:00
ChsBuffer
513d0b01a7 refactor: mode match 2020-12-15 17:12:15 +08:00
ChsBuffer
a3d309113c fix: force using ss-libev if using plugin 2020-12-15 17:11:25 +08:00
ChsBuffer
e77a40966c update LangVersion to 9 2020-12-15 17:05:40 +08:00
ChsBuffer
670cb06e4a fix: auto change server type to ss 2020-12-15 16:29:44 +08:00
AmazingDM
59b4ba578b Update UA 2020-12-09 12:00:51 +08:00
ChsBuffer
5ed25de9ee fix: hardcode tls SecurityProtocol tls1.2 and tls 1.3 2020-12-07 17:50:08 +08:00
ChsBuffer
464abef28a Deprecated: VMess.TLSSecure 2020-12-04 00:02:28 +08:00
ChsBuffer
79a7273af2 feat: Proess Mode Start and Edit Rule check 2020-11-30 17:45:00 +08:00
Connection Refused
7d44821e57 Update README.zh-CN.md 2020-11-30 03:20:29 +08:00
Connection Refused
ca3502a284 Update README.md 2020-11-30 03:19:57 +08:00
Connection Refused
415fc5fa8f Update README.md 2020-11-30 03:19:17 +08:00
ChsBuffer
cfd458ffbd feat: keep server remark empty 2020-11-29 17:49:42 +08:00
ChsBuffer
3be5f10ed8 feat: ProcessMode Bypass Rule keyword 2020-11-29 17:25:47 +08:00
ChsBuffer
41479275da feat: DNS port check before start AioDNS 2020-11-29 17:25:06 +08:00
ChsBuffer
639fcf9575 fix: let SettingForm skip saving DNS value when UseCustomDNS is not enabled 2020-11-29 16:10:23 +08:00
AmazingDM
1eebb61d04 bump version to 1.6.7 2020-11-24 17:52:48 +08:00
AmazingDM
a2a66675c2 Update v2ray 4.33.0 2020-11-24 17:50:04 +08:00
ChsBuffer
850393ab71 refactor: TestFakeDNS 2020-11-15 00:38:29 +08:00
ChsBuffer
ea0dd3cd4a fix: Test project 2020-11-14 23:19:21 +08:00
ChsBuffer
c2afc1b014 fix: load config check if Server node is null 2020-11-14 19:52:44 +08:00
Bruce Wayne
7b9d9a6d57 Update CI 2020-11-14 16:51:18 +08:00
Bruce Wayne
860482402a More accurate TCPing 2020-11-14 16:51:13 +08:00
Bruce Wayne
a58f7c7b98 Use Safehandle job api
No handle leak
2020-11-14 16:51:08 +08:00
Bruce Wayne
6afc5e5e4d Update Nuget packages 2020-11-14 16:08:49 +08:00
ChsBuffer
98a5e91dd2 fix: Visual Studio warn solution contains incorrect configurations mappings 2020-11-11 23:27:27 +08:00
ChsBuffer
9581a41007 refactor: SettingForm AutoScaleMode,Disable Maximize SettingForm 2020-11-11 23:24:51 +08:00
ChsBuffer
d85b478868 doc: update bug report issue template 2020-11-10 23:44:08 +08:00
ChsBuffer
628dd6963a refactor: upgrade NetchLib.csproj to new format 2020-11-10 23:26:05 +08:00
ChsBuffer
5ae6f73062 fix: Netch GSF V2Ray TLSSecure 2020-11-05 23:59:39 +08:00
ChsBuffer
50b07ebabb refactor: GenerateClientConfig 2020-11-05 23:12:45 +08:00
ChsBuffer
21f2f8da5e refactor: extract Netch.Utils.Subscription 2020-11-05 16:13:30 +08:00
ChsBuffer
cfc070b1ef fix: clear DNS Cache wont clean system dns cache 2020-11-05 15:41:05 +08:00
ChsBuffer
a4f024df69 refactor: clean temp config file when exit 2020-11-05 15:04:54 +08:00
ChsBuffer
6754268714 feat: setting saving ignore null value 2020-11-05 14:31:45 +08:00
ChsBuffer
642cd57b71 fix: V2ray ServerForm Use Mux value 2020-11-05 14:31:37 +08:00
ChsBuffer
39ea679298 fix: VMess GetShareLink 2020-11-04 21:52:40 +08:00
ChsBuffer
1091486877 feat: #431 2020-11-04 21:50:18 +08:00
ChsBuffer
d805a4fccd bump version to 1.6.6 2020-10-31 22:18:40 +08:00
ChsBuffer
902f78b563 fix: SSDLL flag
fix: let Trojan don't use AutoresolveHostname setting
2020-10-29 16:30:21 +08:00
ChsBuffer
159fbdd58d feat: ServerForm set the color of the control to red If the value is wrong 2020-10-29 14:56:26 +08:00
ChsBuffer
0c5464f833 refactor: extract RegisterNetchStartupItem() method 2020-10-29 14:47:45 +08:00
ChsBuffer
b019362f5f refactor: Check STUN Server setting 2020-10-29 14:46:39 +08:00
ChsBuffer
241371c6f7 feat: SettingForm set the color of the control to red If the value is wrong 2020-10-29 14:14:50 +08:00
ChsBuffer
9b3f5f456f refactor: Bandwidth.NetTraffic 2020-10-29 13:44:30 +08:00
ChsBuffer
c04b8f6ffd refactor: Check NF driver version 2020-10-29 13:27:33 +08:00
ChsBuffer
9d6b6d15d7 refactor: set StatusPortInfoText.ShareLan 2020-10-29 12:07:12 +08:00
ChsBuffer
39081c0a6f refactor: StatusPortInfoText.Value 2020-10-28 01:43:33 +08:00
ChsBuffer
812fab6322 fix: ModifiedDNS Setting init Enabled state 2020-10-27 18:42:41 +08:00
ChsBuffer
bfadb181c4 fix: SettingForm TUNTAPDNS value init
fix: show starting tun2socks after setup route table
fix: a typo
2020-10-27 12:14:10 +08:00
ChsBuffer
52ac05ee17 feat: add ChildProcessTracker 2020-10-26 17:36:50 +08:00
ChsBuffer
c774122fdb fix: Disable update ACL after startup 2020-10-26 16:58:45 +08:00
ChsBuffer
8e223faa71 fix: v2ray will proxy multicast address causing loop 2020-10-25 21:35:07 +08:00
ChsBuffer
7b0f0f35cc fix: SettingForm load RedriectorTCP value wrong
fix: Start Profile ModeComboBox.Text and ProfileNameText.Text wrong
2020-10-25 21:01:21 +08:00
ChsBuffer
89ce721d4c fix: language setting not saved 2020-10-25 00:24:40 +08:00
ChsBuffer
2247a75269 bump version to 1.6.5 2020-10-24 16:06:13 +08:00
ChsBuffer
c1e9856e92 refactor: check and build dns string 2020-10-23 18:32:06 +08:00
ChsBuffer
41e74e0794 feat: Add setting ”Modified DNS“ for Process Mode 2020-10-23 17:46:31 +08:00
ChsBuffer
6f8214951a fix: update subscription async warning 2020-10-23 17:20:58 +08:00
ChsBuffer
0fc5b77004 refactor: Regenerate SettingForm designer code 2020-10-23 16:35:49 +08:00
ChsBuffer
34cbcbfb0f fix: SettingForm Control Order 2020-10-23 16:30:21 +08:00
ChsBuffer
1ad4a08a85 fix: Edit subscription link shows "Remark Name Duplicate!" 2020-10-23 14:46:16 +08:00
ChsBuffer
8e0bc8e260 feat: Notification update subscription exception status code 2020-10-23 14:45:30 +08:00
ChsBuffer
bae9ecfe88 fix: ImportServerFromClipboard parse twice 2020-10-23 14:36:43 +08:00
ChsBuffer
3ca3e45ce2 feat: Add AioDNS Setting 2020-10-23 13:48:33 +08:00
ChsBuffer
bcb220bc4b Revert "refactor: MainForm change Enabled to change State"
This reverts commit abfae4a9a0.
2020-10-23 12:36:46 +08:00
AmazingDM
c50eb32828 Update README.md 2020-10-23 10:19:53 +08:00
ChsBuffer
b96f171b47 fix: V2RayConfigUtils direct outbound config
refactor: rename VMessController Name V2Ray to VMess
2020-10-22 21:31:20 +08:00
ChsBuffer
4fbbd1dbd4 feat: update progress check hash 2020-10-22 15:17:26 +08:00
ChsBuffer
2ad394dfde refactor: builder dns string and Mode FileString 2020-10-22 15:17:26 +08:00
ChsBuffer
421b35a797 fix: SettingForm UseCustomDNSCheckBox click event is not bound 2020-10-22 15:17:26 +08:00
Connection Refused
25612df086 Update v2ray-core 4.31.2 2020-10-22 13:24:43 +08:00
ChsBuffer
4ac5065ce4 feat: add UseMux Setting 2020-10-21 22:18:11 +08:00
ChsBuffer
d4b97a99e0 feat: V2Ray AllowInsecure Setting 2020-10-21 22:09:53 +08:00
ChsBuffer
3d49fe0338 Revert "feat: V2Ray TLS AllowInsecure Setting"
This reverts commit 591f8e5a5c.
2020-10-21 22:07:58 +08:00
71 changed files with 2626 additions and 1514 deletions

View File

@@ -6,4 +6,54 @@ root = true
# all files
[*]
indent_style = space
indent_size = 4
indent_size = 4
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_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_qualification_for_event = false:suggestion
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
# ReSharper properties
resharper_blank_lines_after_block_statements = 0
resharper_csharp_blank_lines_around_field = 0
resharper_csharp_blank_lines_around_invocable = 0
resharper_csharp_blank_lines_around_type = 0
resharper_csharp_int_align_comments = true
resharper_csharp_max_line_length = 368
resharper_csharp_wrap_lines = false
resharper_place_expr_accessor_on_single_line = true
resharper_place_expr_method_on_single_line = true
resharper_place_field_attribute_on_same_line = false
resharper_place_simple_embedded_statement_on_same_line = false
resharper_place_simple_initializer_on_single_line = false
resharper_use_indent_from_vs = false
resharper_wrap_array_initializer_style = chop_if_long
resharper_wrap_object_and_collection_initializer_style = chop_always
# ReSharper inspection severities
resharper_arrange_redundant_parentheses_highlighting = hint
resharper_arrange_this_qualifier_highlighting = hint
resharper_arrange_type_member_modifiers_highlighting = hint
resharper_arrange_type_modifiers_highlighting = hint
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
resharper_built_in_type_reference_style_highlighting = hint
resharper_redundant_base_qualifier_highlighting = warning
resharper_suggest_var_or_type_built_in_types_highlighting = hint
resharper_suggest_var_or_type_elsewhere_highlighting = hint
resharper_suggest_var_or_type_simple_types_highlighting = hint
resharper_web_config_module_not_resolved_highlighting = warning
resharper_web_config_type_not_resolved_highlighting = warning
resharper_web_config_wrong_module_highlighting = warning

View File

@@ -2,15 +2,13 @@
name: 'Bug report'
about: 'Create a report to help us improve'
title: ''
labels: 'Status: Review Needed'
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.**
**All issues about `bin/Redirector.exe` should be discussed at [issue #152](https://github.com/NetchX/Netch/issues/152).**
**Describe the bug**
A clear and concise description of what the bug is.

View File

@@ -2,15 +2,13 @@
name: '错误报告'
about: '创建错误报告以帮助我们改进'
title: ''
labels: 'Status: Review Needed'
labels: '需要核实'
assignees: ''
---
**确保你已经看过 readme也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
**所有关于 `bin/Redirector.exe` 的问题,请在 [issue #152](https://github.com/NetchX/Netch/issues/152) 中讨论**
**错误描述**
对错误的清晰简洁描述

View File

@@ -14,26 +14,32 @@ jobs:
submodules: true
- name: Build Solution
shell: pwsh
run: .\BUILD.ps1
- name: Upload Artifact
continue-on-error: true
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: actions/upload-artifact@v2
with:
name: Netch
path: Netch\bin\x64\Release
- name: Package
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
shell: pwsh
run: |
.\BUILD.ps1
New-Item -ItemType Directory -Path C:\builtfiles -Force > $null
7z a -mx9 C:\builtfiles\Netch.7z .\Netch\bin\x64\Release\
7z rn C:\builtfiles\Netch.7z Release Netch
echo "Netch_SHA256=$(.\GetSHA256.ps1 C:\builtfiles\Netch.7z)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "Netch_EXE_SHA256=$(.\GetSHA256.ps1 Netch\bin\x64\Release\Netch.exe)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: Netch
path: Netch\bin\x64\Release
- name: Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
if: startsWith(github.ref, 'refs/tags/')
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
with:
name: ${{ env.GITHUB_TAG_NAME }}
prerelease: true
@@ -49,23 +55,4 @@ jobs:
## 校验和
| 文件名 | SHA256 |
| :- | :- |
| Netch.7z | ${{ env.Netch_SHA256 }} |
# Deploy:
# needs: [build]
# runs-on: ubuntu-latest
# steps:
# - name: Download Artifacts
# uses: actions/download-artifact@v1
# with:
# name: Netch
# - name: Pushes to another repository
# uses: peaceiris/actions-gh-pages@v3
# with:
# personal_token: ${{ secrets.ACCESS_TOKEN }}
# publish_branch: repo
# publish_dir: ./Netch
# external_repository: ${{ github.repository_owner }}/NetchReleases
# user_name: 'github-actions[bot]'
# user_email: 'github-actions[bot]@users.noreply.github.com'
| Netch.7z | ${{ env.Netch_SHA256 }} |

View File

@@ -5,11 +5,11 @@ VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetchLib", "NetchLib\NetchLib.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetchLib", "NetchLib\NetchLib.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetchUpdater", "NetchUpdater\NetchUpdater.csproj", "{828318A8-9B90-4A5F-BD6B-E632CC9D8933}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetchUpdater", "NetchUpdater\NetchUpdater.csproj", "{828318A8-9B90-4A5F-BD6B-E632CC9D8933}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -29,10 +29,9 @@ Global
{828318A8-9B90-4A5F-BD6B-E632CC9D8933}.Debug|x64.Build.0 = Debug|x64
{828318A8-9B90-4A5F-BD6B-E632CC9D8933}.Release|x64.ActiveCfg = Release|x64
{828318A8-9B90-4A5F-BD6B-E632CC9D8933}.Release|x64.Build.0 = Release|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|Any CPU
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|Any CPU
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|Any CPU
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.Build.0 = Release|Any CPU
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -6,7 +6,6 @@ namespace Netch.Controllers
{
public class DNSController : IController
{
public string Name { get; } = "DNS Service";
/// <summary>
@@ -15,13 +14,14 @@ namespace Netch.Controllers
/// <returns></returns>
public bool Start()
{
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath("bin\\china_site_list")),
Encoding.UTF8.GetBytes("223.5.5.5:53"),
Encoding.UTF8.GetBytes("1.1.1.1:53"))
)
return false;
return
aiodns_init();
aiodns_dial((int) NameList.TYPE_REST, null);
aiodns_dial((int) NameList.TYPE_ADDR, Encoding.UTF8.GetBytes($"{Global.Settings.LocalAddress}:53"));
aiodns_dial((int) NameList.TYPE_LIST, Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)));
aiodns_dial((int) NameList.TYPE_CDNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"));
aiodns_dial((int) NameList.TYPE_ODNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"));
aiodns_dial((int) NameList.TYPE_METH, Encoding.UTF8.GetBytes(Global.Settings.AioDNS.Protocol));
return aiodns_init();
}
public void Stop()
@@ -32,7 +32,7 @@ namespace Netch.Controllers
#region NativeMethods
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aiodns_dial(byte[] chinacon, byte[] chinadns, byte[] otherdns);
public static extern bool aiodns_dial(int name, byte[] value);
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aiodns_init();
@@ -40,6 +40,16 @@ namespace Netch.Controllers
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern void aiodns_free();
enum NameList : int
{
TYPE_REST,
TYPE_ADDR,
TYPE_LIST,
TYPE_CDNS,
TYPE_ODNS,
TYPE_METH
}
#endregion
}
}

View File

@@ -56,7 +56,7 @@ namespace Netch.Controllers
/// 程序输出的编码,
/// 调用于基类的 <see cref="OnOutputDataReceived"/>
/// </summary>
protected string InstanceOutputEncoding { get; set; } = "gbk";
protected Encoding InstanceOutputEncoding { get; set; } = Encoding.GetEncoding("gbk");
/// <summary>
/// 停止进程
@@ -93,10 +93,11 @@ namespace Netch.Controllers
WorkingDirectory = $"{Global.NetchDir}\\bin",
Arguments = argument,
CreateNoWindow = true,
RedirectStandardError = RedirectStd,
RedirectStandardInput = RedirectStd,
RedirectStandardOutput = RedirectStd,
UseShellExecute = !RedirectStd,
RedirectStandardOutput = RedirectStd,
StandardOutputEncoding = RedirectStd ? InstanceOutputEncoding : null,
RedirectStandardError = RedirectStd,
StandardErrorEncoding = RedirectStd ? InstanceOutputEncoding : null,
WindowStyle = ProcessWindowStyle.Hidden
}
};
@@ -192,15 +193,13 @@ namespace Netch.Controllers
if (e.Data == null)
return;
var info = Encoding.GetEncoding(InstanceOutputEncoding).GetBytes(e.Data);
var str = Encoding.UTF8.GetString(info);
Write(str);
Write(e.Data);
// 检查启动
if (State == State.Starting)
{
if (StartedKeywords.Any(s => str.Contains(s)))
if (StartedKeywords.Any(s => e.Data.Contains(s)))
State = State.Started;
else if (StoppedKeywords.Any(s => str.Contains(s)))
else if (StoppedKeywords.Any(s => e.Data.Contains(s)))
State = State.Stopped;
}
}

View File

@@ -1,11 +1,12 @@
using System;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
using WindowsProxy;
using Netch.Utils.HttpProxyHandler;
namespace Netch.Controllers
{
@@ -31,9 +32,28 @@ namespace Netch.Controllers
try
{
pPrivoxyController.Start(MainController.ServerController.Server, mode);
if (pPrivoxyController.Start(MainController.Server, mode))
{
Global.Job.AddProcess(pPrivoxyController.Instance);
}
if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions);
if (mode.Type == 3)
{
if (mode.BypassChina)
{
//启动PAC服务器
PACServerHandle.InitPACServer("127.0.0.1");
}
else
{
using var service = new ProxyService
{
Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}",
Bypass = IEProxyExceptions
};
service.Global();
}
}
}
catch (Exception e)
{
@@ -82,18 +102,36 @@ namespace Netch.Controllers
{
var tasks = new[]
{
Task.Factory.StartNew(pPrivoxyController.Stop),
Task.Factory.StartNew(() =>
Task.Run(pPrivoxyController.Stop),
Task.Run(() =>
{
if (prevEnabled)
using var service = new ProxyService();
try
{
if (prevHTTP != "")
NativeMethods.SetGlobal(prevHTTP, prevBypass);
if (prevPAC != "")
NativeMethods.SetURL(prevPAC);
PACServerHandle.Stop();
if (prevEnabled)
{
if (prevHTTP != "")
{
service.Server = prevHTTP;
service.Bypass = prevBypass;
service.Global();
}
if (prevPAC != "")
{
service.AutoConfigUrl = prevPAC;
service.Pac();
}
}
else
{
service.Direct();
}
}
catch (Exception e)
{
Logging.Error($"{Name} 控制器出错:\n" + e);
}
else
NativeMethods.SetDIRECT();
})
};
Task.WaitAll(tasks);

View File

@@ -4,8 +4,6 @@ namespace Netch.Controllers
{
public interface IServerController : IController
{
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }

View File

@@ -1,6 +1,7 @@
using System;
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Netch.Models;
using Netch.Servers.Socks5;
@@ -18,12 +19,29 @@ namespace Netch.Controllers
private set => _serverController = value;
}
public static IServerController UdpServerController
{
get => _udpServerController ?? _serverController;
set => _udpServerController = value;
}
/// TCP or Both Server
public static Server Server;
public static Server UdpServer
{
get => _udpServer ?? Server;
set => _udpServer = value;
}
private static Server _udpServer;
public static IModeController ModeController { get; private set; }
public static bool NttTested;
private static readonly NTTController NTTController = new NTTController();
private static IServerController _serverController;
private static IServerController _udpServerController;
/// <summary>
/// 启动
@@ -34,6 +52,7 @@ namespace Netch.Controllers
public static async Task<bool> Start(Server server, Mode mode)
{
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
Server = server;
if (server is Socks5 && mode.Type == 4)
{
@@ -64,17 +83,22 @@ namespace Netch.Controllers
try
{
if (!await Task.Run(() => StartServer(server, mode, ref _serverController)))
if (!ModeHelper.SkipServerController(server, mode))
{
if (!await Task.Run(() => StartServer(server, mode, ref _serverController)))
{
throw new StartFailedException();
}
StatusPortInfoText.UpdateShareLan();
}
if (!await StartMode(mode))
{
throw new StartFailedException();
}
if (!await StartMode(server, mode))
{
throw new StartFailedException();
}
if (mode.TestNatRequired)
if (mode.TestNatRequired())
NatTest();
return true;
@@ -122,8 +146,27 @@ namespace Netch.Controllers
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
if (controller.Start(in server, mode))
{
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
StatusPortInfoText.ShareLan = controller.LocalAddress == "0.0.0.0";
if (controller is Guard guard)
{
if (guard.Instance != null)
{
Task.Run(() =>
{
Thread.Sleep(1000);
Global.Job.AddProcess(guard.Instance);
});
}
}
if (server is Socks5 socks5)
{
if (socks5.Auth())
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
}
else
{
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
}
return true;
}
@@ -131,22 +174,36 @@ namespace Netch.Controllers
return false;
}
private static async Task<bool> StartMode(Server server, Mode mode)
private static async Task<bool> StartMode(Mode mode)
{
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName, out var portType);
if (ModeController == null)
{
return true;
}
if (port != null)
{
PortCheckAndShowMessageBox((ushort) port, portName, portType);
UsingPorts.Add((ushort) port);
}
if (ModeController != null)
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
if (await Task.Run(() => ModeController.Start(mode)))
{
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
return await Task.Run(() => ModeController.Start(mode));
if (ModeController is Guard guard)
{
if (guard.Instance != null)
{
Global.Job.AddProcess(guard.Instance);
}
}
return true;
}
return true;
return false;
}
/// <summary>
@@ -178,7 +235,7 @@ namespace Netch.Controllers
/// <param name="portName">端口用途名称</param>
/// <param name="portType"></param>
/// <exception cref="PortInUseException"></exception>
private static void PortCheckAndShowMessageBox(ushort port, string portName, PortType portType = PortType.Both)
public static void PortCheckAndShowMessageBox(ushort port, string portName, PortType portType = PortType.Both)
{
if (PortInUse(port, portType))
{

View File

@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Threading.Tasks;
using Netch.Forms;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
using Netch.Utils;
using nfapinet;
@@ -46,6 +48,98 @@ namespace Netch.Controllers
}
public bool Start(in Mode mode)
{
if (!CheckDriver())
return false;
#region aio_dial
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp) MessageBoxX.Show("");
//UDP
if (Global.Settings.ProcessNoProxyForUdp)
{
aio_dial((int) NameList.TYPE_FILTERUDP, "false");
SetServer(PortType.TCP);
}
else
{
aio_dial((int) NameList.TYPE_FILTERUDP, "true");
SetServer(PortType.Both);
}
//TCP
if (Global.Settings.ProcessNoProxyForTcp)
{
aio_dial((int) NameList.TYPE_FILTERTCP, "false");
SetServer(PortType.UDP);
}
else
{
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
SetServer(PortType.Both);
}
if (!CheckRule(mode.FullRule, out var list))
{
MessageBoxX.Show($"\"{string.Join("", list.Select(s => s + "\n"))}\" does not conform to C++ regular expression syntax");
return false;
}
SetName(mode);
#endregion
if (Global.Settings.ModifySystemDNS)
{
// 备份并替换系统 DNS
_sysDns = DNS.OutboundDNS;
if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS))
Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8";
DNS.OutboundDNS = Global.Settings.ModifiedDNS;
}
return aio_init();
}
/// <summary>
///
/// </summary>
/// <param name="rules"></param>
/// <param name="incompatibleRule"></param>
/// <returns>No Problem true</returns>
public static bool CheckRule(IEnumerable<string> rules, out IEnumerable<string> incompatibleRule)
{
incompatibleRule = rules.Where(r => !CheckCppRegex(r, false));
aio_dial((int) NameList.TYPE_CLRNAME, "");
return !incompatibleRule.Any();
}
/// <summary>
///
/// </summary>
/// <param name="r"></param>
/// <param name="clear"></param>
/// <returns>No Problem true</returns>
public static bool CheckCppRegex(string r, bool clear = true)
{
try
{
if (r.StartsWith("!"))
return aio_dial((int) NameList.TYPE_ADDNAME, r.Substring(1));
return aio_dial((int) NameList.TYPE_ADDNAME, r);
}
finally
{
if (clear)
aio_dial((int) NameList.TYPE_CLRNAME, "");
}
}
private static bool CheckDriver()
{
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
@@ -53,64 +147,107 @@ namespace Netch.Controllers
Logging.Info("内置驱动版本: " + binFileVersion);
Logging.Info("系统驱动版本: " + systemFileVersion);
if (!systemFileVersion.Equals(binFileVersion))
if (!File.Exists(BinDriver))
{
Logging.Warning("内置驱动不存在");
if (File.Exists(SystemDriver))
{
Logging.Info("更新驱动");
UninstallDriver();
Logging.Warning("使用系统驱动");
return true;
}
if (!InstallDriver())
return false;
Logging.Error("未安装驱动");
return false;
}
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
aio_dial((int) NameList.TYPE_FILTERUDP, "true");
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
SetServer(MainController.ServerController, PortType.Both);
SetName(mode);
if (Global.Settings.ModifySystemDNS)
if (!File.Exists(SystemDriver))
{
// 备份并替换系统 DNS
_sysDns = DNS.OutboundDNS;
DNS.OutboundDNS = "1.1.1.1,8.8.8.8";
return InstallDriver();
}
return aio_init();
}
var updateFlag = false;
private void SetServer(in IServerController controller, in PortType portType)
{
if (portType == PortType.Both)
if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
{
SetServer(controller, PortType.TCP);
SetServer(controller, PortType.UDP);
return;
}
var offset = portType == PortType.UDP ? UdpNameListOffset : 0;
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
if (controller.Server is Socks5 socks5)
{
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
aio_dial((int) NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
aio_dial((int) NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
if (binResult.CompareTo(systemResult) > 0)
{
// Bin greater than Installed
updateFlag = true;
}
else
{
// Installed greater than Bin
if (systemResult.Major != binResult.Major)
{
// API breaking changes
updateFlag = true;
}
}
}
else
{
if (!systemFileVersion.Equals(binFileVersion))
{
updateFlag = true;
}
}
if (!updateFlag) return true;
Logging.Info("更新驱动");
UninstallDriver();
return InstallDriver();
}
private void SetServer(in PortType portType)
{
if (portType == PortType.Both)
{
SetServer(PortType.TCP);
SetServer(PortType.UDP);
return;
}
int offset;
Server server;
IServerController controller;
if (portType == PortType.UDP)
{
offset = UdpNameListOffset;
server = MainController.UdpServer;
controller = MainController.UdpServerController;
}
else
{
offset = 0;
server = MainController.Server;
controller = MainController.ServerController;
}
if (server is Socks5 socks5)
{
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
aio_dial((int) NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
aio_dial((int) NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
}
else if (server is Shadowsocks shadowsocks && !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS)
{
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
aio_dial((int) NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod ?? string.Empty);
aio_dial((int) NameList.TYPE_TCPPASS + offset, shadowsocks.Password ?? string.Empty);
}
else
{
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"127.0.0.1:{controller.Socks5LocalPort()}");
aio_dial((int) NameList.TYPE_TCPUSER + offset, string.Empty);
aio_dial((int) NameList.TYPE_TCPPASS + offset, string.Empty);
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
}
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
}
private void SetName(Mode mode)
@@ -118,10 +255,16 @@ namespace Netch.Controllers
aio_dial((int) NameList.TYPE_CLRNAME, "");
foreach (var rule in mode.FullRule)
{
if (rule.StartsWith("!"))
{
aio_dial((int) NameList.TYPE_BYPNAME, rule.Substring(1));
continue;
}
aio_dial((int) NameList.TYPE_ADDNAME, rule);
}
aio_dial((int) NameList.TYPE_ADDNAME, "NTT.exe");
aio_dial((int) NameList.TYPE_ADDNAME, @"NTT\.exe");
}
public void Stop()
@@ -141,19 +284,19 @@ namespace Netch.Controllers
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aio_init();
private static extern bool aio_init();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aio_free();
private static extern bool aio_free();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong aio_getUP();
private static extern ulong aio_getUP();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong aio_getDL();
private static extern ulong aio_getDL();
public enum NameList : int

View File

@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Netch.Utils;
@@ -7,10 +8,6 @@ namespace Netch.Controllers
{
public class NTTController : Guard, IController
{
private string _localEnd;
private string _publicEnd;
private string _result;
private string _bindingTest;
public override string Name { get; protected set; } = "NTT";
public override string MainFile { get; protected set; } = "NTT.exe";
@@ -20,7 +17,10 @@ namespace Netch.Controllers
/// <returns></returns>
public (string, string, string) Start()
{
_result = _localEnd = _publicEnd = null;
string localEnd=null;
string publicEnd=null;
string result =null;
string bindingTest=null;
try
{
@@ -28,12 +28,50 @@ namespace Netch.Controllers
Instance.OutputDataReceived += OnOutputDataReceived;
Instance.ErrorDataReceived += OnOutputDataReceived;
Instance.Start();
Instance.BeginOutputReadLine();
Instance.BeginErrorReadLine();
Instance.WaitForExit();
if (_bindingTest == "Fail")
_result = "UdpBlocked";
return (_result, _localEnd, _publicEnd);
var output = Instance.StandardOutput.ReadToEnd();
try
{
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), output);
}
catch (Exception e)
{
Logging.Warning($"写入 {Name} 日志错误:\n" + e.Message);
}
foreach (var line in output.Split('\n'))
{
var str = line.Split(':').Select(s => s.Trim()).ToArray();
if (str.Length < 2)
continue;
var key = str[0];
var value = str[1];
switch (key)
{
case "Other address is":
case "Nat mapping behavior":
case "Nat filtering behavior":
break;
case "Binding test":
bindingTest = value;
break;
case "Local address":
localEnd = value;
break;
case "Mapped address":
publicEnd = value;
break;
case "result":
result = value;
break;
default:
result = str.Last();
break;
}
}
if (bindingTest == "Fail")
result = "UdpBlocked";
return (result, localEnd, publicEnd);
}
catch (Exception e)
{
@@ -51,41 +89,6 @@ namespace Netch.Controllers
}
}
private new void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data)) return;
Logging.Info($"[NTT] {e.Data}");
var str = e.Data.Split(':').Select(s => s.Trim()).ToArray();
if (str.Length < 2)
return;
var key = str[0];
var value = str[1];
switch (key)
{
case "Other address is":
case "Nat mapping behavior":
case "Nat filtering behavior":
break;
case "Binding test":
_bindingTest = value;
break;
case "Local address":
_localEnd = value;
break;
case "Mapped address":
_publicEnd = value;
break;
case "result":
_result = value;
break;
default:
_result = str.Last();
break;
}
}
public override void Stop()
{
StopInstance();

View File

@@ -2,6 +2,7 @@
using System.Text;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils.HttpProxyHandler;
namespace Netch.Controllers
{

View File

@@ -1,14 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
@@ -17,9 +15,7 @@ namespace Netch.Controllers
{
public class TUNTAPController : Guard, IModeController
{
private Mode _savedMode = new Mode();
private Server _savedServer = new Server();
/// <summary>
/// 服务器 IP 地址
/// </summary>
@@ -41,11 +37,9 @@ namespace Netch.Controllers
public bool Start(in Mode mode)
{
_savedMode = mode;
_savedServer = MainController.ServerController.Server;
var server = MainController.Server;
// 查询服务器 IP 地址
_serverAddresses = DNS.Lookup(_savedServer.Hostname);
_serverAddresses = DNS.Lookup(server.Hostname);
// 查找出口适配器
if (!Utils.Utils.SearchOutboundAdapter())
@@ -66,14 +60,16 @@ namespace Netch.Controllers
}
SetupRouteTable();
SetupRouteTable(mode);
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", Name));
string dns;
if (Global.Settings.TUNTAP.UseCustomDNS)
{
if (Global.Settings.TUNTAP.DNS.Any())
{
dns = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
dns = DNS.Join(Global.Settings.TUNTAP.DNS);
}
else
{
@@ -83,13 +79,27 @@ namespace Netch.Controllers
}
else
{
var _ = DNSController.Start();
try
{
MainController.PortCheckAndShowMessageBox(53, "DNS");
}
catch
{
return false;
}
if (!DNSController.Start())
{
Logging.Error("AioDNS 启动失败");
return false;
}
dns = "127.0.0.1";
}
var argument = new StringBuilder();
if (_savedServer is Socks5 socks5 && !socks5.Auth())
argument.Append($"-proxyServer {_serverAddresses}:{_savedServer.Port} ");
if (server is Socks5 socks5 && !socks5.Auth())
argument.Append($"-proxyServer {server.AutoResolveHostname()}:{server.Port} ");
else
argument.Append($"-proxyServer 127.0.0.1:{Global.Settings.Socks5LocalPort} ");
@@ -109,9 +119,9 @@ namespace Netch.Controllers
{
var tasks = new[]
{
Task.Factory.StartNew(StopInstance),
Task.Factory.StartNew(ClearRouteTable),
Task.Factory.StartNew(DNSController.Stop)
Task.Run(StopInstance),
Task.Run(ClearRouteTable),
Task.Run(DNSController.Stop)
};
Task.WaitAll(tasks);
}
@@ -124,73 +134,75 @@ namespace Netch.Controllers
/// 设置绕行规则
/// </summary>
/// <returns>是否设置成功</returns>
private void SetupRouteTable()
private void SetupRouteTable(Mode mode)
{
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
Logging.Info("设置路由规则");
#region Rule IPs
if (_savedMode.Type == 1)
switch (mode.Type)
{
// 代理规则
Logging.Info("代理 → 规则 IP");
RouteAction(Action.Create, _savedMode.FullRule, RouteType.TUNTAP);
case 1:
// 代理规则
Logging.Info("代理 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP自己记录解析了返回的 IP仅支持默认检测服务器
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
{
try
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP自己记录解析了返回的 IP仅支持默认检测服务器
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
{
Logging.Info("代理 → STUN 服务器 IP");
RouteAction(Action.Create,
new[]
{
Dns.GetHostAddresses(Global.Settings.STUN_Server)[0],
Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0]
}.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
try
{
Logging.Info("代理 → STUN 服务器 IP");
RouteAction(Action.Create,
new[]
{
Dns.GetHostAddresses(Global.Settings.STUN_Server)[0],
Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0]
}.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
catch
{
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
}
}
catch
{
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
}
}
if (Global.Settings.TUNTAP.ProxyDNS)
{
Logging.Info("代理 → 自定义 DNS");
if (Global.Settings.TUNTAP.UseCustomDNS)
if (Global.Settings.TUNTAP.ProxyDNS)
{
RouteAction(Action.Create,
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
Logging.Info("代理 → 自定义 DNS");
if (Global.Settings.TUNTAP.UseCustomDNS)
{
RouteAction(Action.Create,
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
else
{
RouteAction(Action.Create,
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
}
else
{
RouteAction(Action.Create,
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
}
}
else if (_savedMode.Type == 2)
{
// 绕过规则
// 将 TUN/TAP 网卡权重放到最高
Process.Start(new ProcessStartInfo
{
FileName = "netsh",
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
CreateNoWindow = true
}
);
break;
case 2:
// 绕过规则
Logging.Info("绕行 → 规则 IP");
RouteAction(Action.Create, _savedMode.FullRule, RouteType.Outbound);
// 将 TUN/TAP 网卡权重放到最高
Process.Start(new ProcessStartInfo
{
FileName = "netsh",
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
CreateNoWindow = true
}
);
Logging.Info("绕行 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
break;
}
#endregion
@@ -202,7 +214,7 @@ namespace Netch.Controllers
Logging.Info("绕行 → 全局绕过 IP");
RouteAction(Action.Create, Global.Settings.BypassIPs, RouteType.Outbound);
if (_savedMode.Type == 2)
if (mode.Type == 2)
{
// 绕过规则
Logging.Info("代理 → 全局");
@@ -226,33 +238,11 @@ namespace Netch.Controllers
public bool TestFakeDNS()
{
var exited = false;
var helpStr = new StringBuilder();
try
{
void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data == null)
{
exited = true;
return;
}
helpStr.Append(e.Data);
}
InitInstance("-h");
// Instance.OutputDataReceived += OnOutputDataReceived;
Instance.ErrorDataReceived += OnOutputDataReceived;
Instance.Start();
Instance.BeginOutputReadLine();
Instance.BeginErrorReadLine();
while (!exited)
{
Thread.Sleep(200);
}
return helpStr.ToString().Contains("-fakeDns");
return Instance.StandardError.ReadToEnd().Contains("-fakeDns");
}
catch
{

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Netch.Models.GitHubRelease;
using Netch.Utils;
@@ -15,14 +16,14 @@ namespace Netch.Controllers
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2020";
public const string AssemblyVersion = @"1.6.4";
public const string AssemblyVersion = @"1.7.0";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
public string LatestVersionNumber;
public string LatestVersionUrl;
public string LatestVersionDownloadUrl;
public Release LatestRelease;
public event EventHandler NewVersionFound;
public event EventHandler NewVersionFoundFailed;
@@ -38,12 +39,11 @@ namespace Netch.Controllers
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
var releases = JsonConvert.DeserializeObject<List<Release>>(json);
var latestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
LatestVersionNumber = latestRelease.tag_name;
LatestVersionUrl = latestRelease.html_url;
LatestVersionDownloadUrl = latestRelease.assets[0].browser_download_url;
Logging.Info($"Github 最新发布版本: {latestRelease.tag_name}");
if (VersionUtil.CompareVersion(latestRelease.tag_name, Version) > 0)
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
LatestVersionNumber = LatestRelease.tag_name;
LatestVersionUrl = LatestRelease.html_url;
Logging.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
{
Logging.Info("发现新版本");
NewVersionFound?.Invoke(this, new EventArgs());

View File

@@ -87,6 +87,7 @@
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl();
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MenuStrip.SuspendLayout();
this.ConfigurationGroupBox.SuspendLayout();
this.configLayoutPanel.SuspendLayout();
@@ -196,6 +197,7 @@
this.CleanDNSCacheToolStripMenuItem,
this.UpdateACLToolStripMenuItem,
this.updateACLWithProxyToolStripMenuItem,
this.updatePACToolStripMenuItem,
this.UninstallServiceToolStripMenuItem,
this.UninstallTapDriverToolStripMenuItem});
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
@@ -441,6 +443,7 @@
this.EditServerPictureBox.Location = new System.Drawing.Point(3, 3);
this.EditServerPictureBox.Name = "EditServerPictureBox";
this.EditServerPictureBox.Size = new System.Drawing.Size(16, 16);
this.EditServerPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.EditServerPictureBox.TabIndex = 7;
this.EditServerPictureBox.TabStop = false;
this.EditServerPictureBox.Click += new System.EventHandler(this.EditServerPictureBox_Click);
@@ -452,6 +455,7 @@
this.CopyLinkPictureBox.Location = new System.Drawing.Point(72, 3);
this.CopyLinkPictureBox.Name = "CopyLinkPictureBox";
this.CopyLinkPictureBox.Size = new System.Drawing.Size(18, 18);
this.CopyLinkPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.CopyLinkPictureBox.TabIndex = 14;
this.CopyLinkPictureBox.TabStop = false;
this.CopyLinkPictureBox.Click += new System.EventHandler(this.CopyLinkPictureBox_Click);
@@ -463,6 +467,7 @@
this.DeleteServerPictureBox.Location = new System.Drawing.Point(26, 3);
this.DeleteServerPictureBox.Name = "DeleteServerPictureBox";
this.DeleteServerPictureBox.Size = new System.Drawing.Size(16, 16);
this.DeleteServerPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.DeleteServerPictureBox.TabIndex = 8;
this.DeleteServerPictureBox.TabStop = false;
this.DeleteServerPictureBox.Click += new System.EventHandler(this.DeleteServerPictureBox_Click);
@@ -474,6 +479,7 @@
this.SpeedPictureBox.Location = new System.Drawing.Point(49, 3);
this.SpeedPictureBox.Name = "SpeedPictureBox";
this.SpeedPictureBox.Size = new System.Drawing.Size(16, 16);
this.SpeedPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.SpeedPictureBox.TabIndex = 9;
this.SpeedPictureBox.TabStop = false;
this.SpeedPictureBox.Click += new System.EventHandler(this.SpeedPictureBox_Click);
@@ -501,6 +507,7 @@
this.EditModePictureBox.Location = new System.Drawing.Point(3, 3);
this.EditModePictureBox.Name = "EditModePictureBox";
this.EditModePictureBox.Size = new System.Drawing.Size(16, 16);
this.EditModePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.EditModePictureBox.TabIndex = 12;
this.EditModePictureBox.TabStop = false;
this.EditModePictureBox.Click += new System.EventHandler(this.EditModePictureBox_Click);
@@ -512,6 +519,7 @@
this.DeleteModePictureBox.Location = new System.Drawing.Point(26, 3);
this.DeleteModePictureBox.Name = "DeleteModePictureBox";
this.DeleteModePictureBox.Size = new System.Drawing.Size(16, 16);
this.DeleteModePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.DeleteModePictureBox.TabIndex = 13;
this.DeleteModePictureBox.TabStop = false;
this.DeleteModePictureBox.Click += new System.EventHandler(this.DeleteModePictureBox_Click);
@@ -691,6 +699,13 @@
this.ButtomControlContainerControl.TabStop = false;
this.ButtomControlContainerControl.Text = "groupBox1";
//
// updatePACToolStripMenuItem
//
this.updatePACToolStripMenuItem.Name = "updatePACToolStripMenuItem";
this.updatePACToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.updatePACToolStripMenuItem.Text = "Update PAC";
this.updatePACToolStripMenuItem.Click += new System.EventHandler(this.updatePACToolStripMenuItem_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -797,5 +812,6 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
private System.Windows.Forms.ToolStripMenuItem updatePACToolStripMenuItem;
}
}

View File

@@ -1,13 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Forms.Mode;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using Netch.Utils.HttpProxyHandler;
using Newtonsoft.Json;
namespace Netch.Forms
{
@@ -26,8 +31,9 @@ namespace Netch.Forms
var texts = Clipboard.GetText();
if (!string.IsNullOrWhiteSpace(texts))
{
Global.Settings.Server.AddRange(ShareLink.ParseText(texts));
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", ShareLink.ParseText(texts).Count));
var servers = ShareLink.ParseText(texts);
Global.Settings.Server.AddRange(servers);
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", servers.Count));
InitServer();
Configuration.Save();
@@ -98,9 +104,7 @@ namespace Netch.Forms
}
private readonly object _serverLock = new object();
public async Task UpdateServersFromSubscribe()
private async Task UpdateServersFromSubscribe()
{
void DisableItems(bool v)
{
@@ -124,9 +128,11 @@ namespace Netch.Forms
StatusText(i18N.Translate("Starting update subscription"));
DisableItems(false);
var useProxyToUpdateSubscription = Global.Settings.UseProxyToUpdateSubscription;
try
{
if (Global.Settings.UseProxyToUpdateSubscription)
string proxyServer = null;
if (useProxyToUpdateSubscription)
{
var mode = new Models.Mode
{
@@ -134,40 +140,10 @@ namespace Netch.Forms
Type = 5
};
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
}
await Task.WhenAll(Global.Settings.SubscribeLink.Select(async item => await Task.Run(async () =>
{
try
{
var request = WebUtil.CreateRequest(item.Link);
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;
if (Global.Settings.UseProxyToUpdateSubscription)
request.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
var servers = ShareLink.ParseText(await WebUtil.DownloadStringAsync(request));
foreach (var server in servers)
{
server.Group = item.Remark;
}
lock (_serverLock)
{
Global.Settings.Server.RemoveAll(server => server.Group.Equals(item.Remark));
Global.Settings.Server.AddRange(servers);
}
NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, servers.Count));
}
catch (Exception e)
{
NotifyTip($"{i18N.TranslateFormat("Update servers error from {0}", item.Remark)}\n{e.Message}", info: false);
Logging.Error(e.ToString());
}
})).ToArray());
await Subscription.UpdateServersAsync(proxyServer);
InitServer();
Configuration.Save();
@@ -179,9 +155,16 @@ namespace Netch.Forms
}
finally
{
if (Global.Settings.UseProxyToUpdateSubscription)
if (useProxyToUpdateSubscription)
{
await MainController.Stop();
try
{
await MainController.Stop();
}
catch
{
// ignored
}
}
DisableItems(true);
@@ -223,7 +206,12 @@ namespace Netch.Forms
{
try
{
await Task.Run(() => DNS.Cache.Clear());
await Task.Run(() =>
{
NativeMethods.FlushDNSResolverCache();
DNS.Cache.Clear();
});
StatusText(i18N.Translate("DNS cache cleanup succeeded"));
}
catch (Exception)
@@ -244,19 +232,13 @@ namespace Netch.Forms
private async void UpdateACL(bool useProxy)
{
void DisableItems(bool v)
{
UpdateACLToolStripMenuItem.Enabled = updateACLWithProxyToolStripMenuItem.Enabled = v;
}
if (useProxy && ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
DisableItems(false);
Enabled = false;
NotifyTip(i18N.Translate("Updating in the background"));
try
@@ -292,42 +274,71 @@ namespace Netch.Forms
State = State.Stopped;
}
DisableItems(true);
Enabled = true;
}
}
private async void updatePACToolStripMenuItem_Click(object sender, EventArgs eventArgs)
{
Enabled = false;
NotifyTip(i18N.Translate("Updating in the background"));
try
{
var req = WebUtil.CreateRequest(Global.Settings.GFWLIST);
string gfwlist = Path.Combine(Global.NetchDir, $"bin\\gfwlist");
string pac = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
await WebUtil.DownloadFileAsync(req, gfwlist);
var gfwContent = File.ReadAllText(gfwlist);
List<string> lines = PACUtil.ParseResult(gfwContent);
string abpContent = PACUtil.UnGzip(Resources.abp_js);
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
File.WriteAllText(pac, abpContent, Encoding.UTF8);
NotifyTip(i18N.Translate("PAC updated successfully"));
}
catch (Exception e)
{
NotifyTip(i18N.Translate("PAC update failed") + "\n" + e.Message, info: false);
Logging.Error("更新 PAC 失败!" + e);
}
finally
{
Enabled = true;
}
}
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
State = State.Starting;
Enabled = false;
StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
var result = false;
try
{
await Task.Run(() =>
{
if (NFController.UninstallDriver())
{
result = true;
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
}
});
}
finally
{
State = State.Stopped;
if (result)
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
Enabled = true;
}
}
private async void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
{
State = State.Starting;
StatusText(i18N.TranslateFormat("Uninstalling {0}", "TUN/TAP driver"));
var result = false;
Enabled = false;
try
{
await Task.Run(TUNTAP.deltapall);
result = true;
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
}
catch (Exception exception)
{
@@ -335,9 +346,8 @@ namespace Netch.Forms
}
finally
{
State = State.Stopped;
if (result)
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
State = State.Waiting;
Enabled = true;
}
}

View File

@@ -2,6 +2,8 @@
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Utils;
@@ -35,7 +37,7 @@ namespace Netch.Forms
private async void NewVersionLabel_Click(object sender, EventArgs e)
{
if (!_updater.LatestVersionDownloadUrl.Contains("Netch"))
if (!_updater.LatestRelease.assets.Any())
{
Utils.Utils.Open(_updater.LatestVersionUrl);
return;
@@ -44,15 +46,38 @@ namespace Netch.Forms
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
return;
NotifyTip(i18N.Translate("Start downloading new version"));
var fileName = Path.GetFileName(new Uri(_updater.LatestVersionDownloadUrl).LocalPath);
var latestVersionDownloadUrl = _updater.LatestRelease.assets[0].browser_download_url;
var tagPage = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(_updater.LatestVersionUrl));
var match = Regex.Match(tagPage, @"<td .*>(?<sha256>.*)</td>", RegexOptions.Singleline);
// TODO Replace with regex get basename and sha256
var fileName = Path.GetFileName(new Uri(latestVersionDownloadUrl).LocalPath);
fileName = fileName.Insert(fileName.LastIndexOf('.'), _updater.LatestVersionNumber);
var fileFullPath = Path.Combine(Global.NetchDir, "data", fileName);
var sha256 = match.Groups["sha256"].Value;
try
{
if (!File.Exists(fileFullPath))
if (File.Exists(fileFullPath))
{
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(_updater.LatestVersionDownloadUrl), fileFullPath);
if (Utils.Utils.SHA256CheckSum(fileFullPath) == sha256)
{
RunUpdater();
return;
}
File.Delete(fileFullPath);
}
// TODO Replace "New Version Found" to Progress bar
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(latestVersionDownloadUrl), fileFullPath);
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
{
MessageBoxX.Show("The downloaded file has the wrong hash");
return;
}
RunUpdater();

View File

@@ -79,7 +79,8 @@ namespace Netch.Forms
private void LoadProfile(int index)
{
var p = Global.Settings.Profiles[index];
ProfileNameText.Text = p.ModeRemark;
ProfileNameText.Text = p.ProfileName;
ModeComboBox.ResetCompletionList();
if (p.IsDummy)
throw new Exception("Profile not found.");
@@ -160,9 +161,6 @@ namespace Netch.Forms
return;
}
// Reset Mode ComboBox Items
ModeComboBox.Text = string.Empty;
try
{
LoadProfile(index);

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Linq;
using Netch.Models;
using Netch.Utils;
@@ -35,10 +36,11 @@ namespace Netch.Forms
// 启动需要禁用的控件
UninstallServiceToolStripMenuItem.Enabled =
updateACLWithProxyToolStripMenuItem.Enabled =
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
UninstallTapDriverToolStripMenuItem.Enabled =
ReloadModesToolStripMenuItem.Enabled = enabled;
UpdateACLToolStripMenuItem.Enabled =
updateACLWithProxyToolStripMenuItem.Enabled =
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
UninstallTapDriverToolStripMenuItem.Enabled =
ReloadModesToolStripMenuItem.Enabled = enabled;
}
_state = value;
@@ -185,12 +187,7 @@ namespace Netch.Forms
{
private static ushort? _socks5Port;
private static ushort? _httpPort;
private static bool? _shareLan;
public static bool ShareLan
{
set => _shareLan = value;
}
private static bool _shareLan;
public static ushort HttpPort
{
@@ -202,35 +199,34 @@ namespace Netch.Forms
set => _socks5Port = value;
}
public static void UpdateShareLan() => _shareLan = Global.Settings.LocalAddress != "127.0.0.1";
public static string Value
{
get
{
if (_socks5Port == null && _httpPort == null)
return string.Empty;
var text = new StringBuilder();
if (_shareLan == true)
text.Append(i18N.Translate("Allow other Devices to connect") + " ");
var strings = new List<string>();
if (_socks5Port != null)
text.Append($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
{
strings.Add($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
}
if (_httpPort != null)
{
if (_socks5Port != null)
text.Append(" | ");
text.Append($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
strings.Add($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
}
return $" ({text})";
if (!strings.Any())
return string.Empty;
return $" ({(_shareLan ? i18N.Translate("Allow other Devices to connect") + " " : "")}{string.Join(" | ", strings)})";
}
}
public static void Reset()
{
_httpPort = _socks5Port = null;
_shareLan = null;
}
}
}

View File

@@ -283,14 +283,19 @@ namespace Netch.Forms
Configuration.Save();
if (File.Exists("data\\last.json"))
File.Delete("data\\last.json");
foreach (var file in new[] {"data\\last.json", "data\\privoxy.conf"})
{
if (File.Exists(file))
File.Delete(file);
}
State = State.Terminating;
}
#region MISC
private bool _resumeFlag;
/// <summary>
/// 监听电源事件自动重启Netch服务
/// </summary>
@@ -298,20 +303,24 @@ namespace Netch.Forms
/// <param name="e"></param>
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
//不对Netch命令等待状态的电源事件做任何处理
if (!State.Equals(State.Waiting))
switch (e.Mode)
{
switch (e.Mode)
{
case PowerModes.Suspend: //操作系统即将挂起
Logging.Info("操作系统即将挂起,自动停止===>" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
case PowerModes.Suspend: //操作系统即将挂起
if (!IsWaiting)
{
_resumeFlag = true;
Logging.Info("操作系统即将挂起,自动停止");
ControlFun();
break;
case PowerModes.Resume: //操作系统即将从挂起状态继续
Logging.Info("操作系统即将从挂起状态继续,自动重启===>" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
}
break;
case PowerModes.Resume: //操作系统即将从挂起状态继续
if (_resumeFlag)
{
_resumeFlag = false;
Logging.Info("操作系统即将从挂起状态继续,自动重启");
ControlFun();
break;
}
}
break;
}
}
@@ -334,7 +343,7 @@ namespace Netch.Forms
private async void SpeedPictureBox_Click(object sender, EventArgs e)
{
State = State.Starting;
Enabled = false;
StatusText(i18N.Translate("Testing"));
try
{
@@ -342,7 +351,7 @@ namespace Netch.Forms
}
finally
{
State = State.Stopped;
Enabled = true;
StatusText(i18N.Translate("Test done"));
Refresh();
}
@@ -357,21 +366,23 @@ namespace Netch.Forms
return;
}
var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
switch (selectedMode.Type)
var mode = (Models.Mode) ModeComboBox.SelectedItem;
if (ModifierKeys == Keys.Control)
{
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath));
return;
}
switch (mode.Type)
{
case 0:
{
Hide();
new Process(selectedMode).ShowDialog();
new Process(mode).ShowDialog();
Show();
break;
}
default:
{
MessageBoxX.Show($"Current not support editing {selectedMode.TypeToString()} Mode");
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath));
break;
}
}
}
@@ -445,7 +456,7 @@ namespace Netch.Forms
if (WindowState == FormWindowState.Minimized)
{
Visible = true;
ShowInTaskbar = true; // 显示在系统任务栏
ShowInTaskbar = true; // 显示在系统任务栏
WindowState = FormWindowState.Normal; // 还原窗体
}
@@ -462,14 +473,14 @@ namespace Netch.Forms
if (WindowState == FormWindowState.Minimized)
{
Visible = true;
ShowInTaskbar = true; //显示在系统任务栏
ShowInTaskbar = true; //显示在系统任务栏
WindowState = FormWindowState.Normal; //还原窗体
}
Activate();
}
private void NotifyTip(string text, int timeout = 0, bool info = true)
public void NotifyTip(string text, int timeout = 0, bool info = true)
{
// 会阻塞线程 timeout 秒
NotifyIcon.ShowBalloonTip(timeout,

View File

@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Dialogs;
using Netch.Controllers;
using Netch.Utils;
namespace Netch.Forms.Mode
@@ -139,23 +140,28 @@ namespace Netch.Forms.Mode
{
await Task.Run(() =>
{
if (!string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
{
var process = ProcessNameTextBox.Text;
if (!RuleListBox.Items.Contains(process))
{
RuleListBox.Items.Add(process);
}
Edited = true;
RuleListBox.SelectedIndex = RuleListBox.Items.IndexOf(process);
ProcessNameTextBox.Text = string.Empty;
}
else
if (string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
{
MessageBoxX.Show(i18N.Translate("Please enter an process name (xxx.exe)"));
return;
}
if (!NFController.CheckCppRegex(ProcessNameTextBox.Text))
{
MessageBoxX.Show("Rule does not conform to C++ regular expression syntax");
return;
}
var process = ProcessNameTextBox.Text;
if (!RuleListBox.Items.Contains(process))
{
RuleListBox.Items.Add(process);
}
Edited = true;
RuleListBox.SelectedIndex = RuleListBox.Items.IndexOf(process);
ProcessNameTextBox.Text = string.Empty;
});
}

View File

@@ -168,28 +168,37 @@ namespace Netch.Forms
private void ControlButton_Click(object sender, EventArgs e)
{
if (_checkActions.All(pair => pair.Value.Invoke(pair.Key.Text)))
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
var flag = true;
foreach (var pair in _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)))
{
foreach (var pair in _saveActions)
{
switch (pair.Key)
{
case CheckBox c:
pair.Value.Invoke(c.Checked);
break;
default:
pair.Value.Invoke(pair.Key.Text);
break;
}
}
if (Global.Settings.Server.IndexOf(Server) == -1)
Global.Settings.Server.Add(Server);
MessageBoxX.Show(i18N.Translate("Saved"));
Utils.Utils.ChangeControlForeColor(pair.Key, Color.Red);
flag = false;
}
else
if (!flag)
{
return;
}
foreach (var pair in _saveActions)
{
switch (pair.Key)
{
case CheckBox c:
pair.Value.Invoke(c.Checked);
break;
default:
pair.Value.Invoke(pair.Key.Text);
break;
}
}
if (Global.Settings.Server.IndexOf(Server) == -1)
Global.Settings.Server.Add(Server);
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,13 @@
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using TaskScheduler;
namespace Netch.Forms
{
@@ -20,8 +21,9 @@ namespace Netch.Forms
}
private void SettingForm2_Load(object sender, EventArgs e)
private void SettingForm_Load(object sender, EventArgs e)
{
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns)));
}
@@ -30,17 +32,17 @@ namespace Netch.Forms
#region General
BindTextBox<ushort>(Socks5PortTextBox,
p => CheckPort("Socks5", p, Global.Settings.Socks5LocalPort),
p => p.ToString() != HTTPPortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
p => Global.Settings.Socks5LocalPort = p,
Global.Settings.Socks5LocalPort);
BindTextBox<ushort>(HTTPPortTextBox,
p => CheckPort("HTTP", p, Global.Settings.HTTPLocalPort),
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
p => Global.Settings.HTTPLocalPort = p,
Global.Settings.HTTPLocalPort);
BindTextBox<ushort>(RedirectorTextBox,
s => CheckPort("RedirectorTCP", s, Global.Settings.RedirectorTCPPort),
s => Global.Settings.RedirectorTCPPort = s,
Global.Settings.HTTPLocalPort);
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != HTTPPortTextBox.Text,
p => Global.Settings.RedirectorTCPPort = p,
Global.Settings.RedirectorTCPPort);
BindCheckBox(AllowDevicesCheckBox,
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
Global.Settings.LocalAddress switch
@@ -50,7 +52,6 @@ namespace Netch.Forms
_ => false
});
BindCheckBox(BootShadowsocksFromDLLCheckBox,
c => Global.Settings.BootShadowsocksFromDLL = c,
Global.Settings.BootShadowsocksFromDLL);
@@ -58,6 +59,14 @@ namespace Netch.Forms
c => Global.Settings.ResolveServerHostname = c,
Global.Settings.ResolveServerHostname);
BindRadioBox(ICMPingRadioBtn,
c => Global.Settings.ServerTCPing = c,
!Global.Settings.ServerTCPing);
BindRadioBox(TCPingRadioBtn,
c => Global.Settings.ServerTCPing = c,
Global.Settings.ServerTCPing);
BindTextBox<int>(ProfileCountTextBox,
i => i > -1,
i => Global.Settings.ProfileCount = i,
@@ -83,13 +92,31 @@ namespace Netch.Forms
#endregion
#region Process Mode
BindCheckBox(ModifySystemDNSCheckBox,
b => Global.Settings.ModifySystemDNS = b,
Global.Settings.ModifySystemDNS);
ModifySystemDNSCheckBox_CheckedChanged(null, null);
BindTextBox(ModifiedDNSTextBox,
s => DNS.TrySplit(s, out _, 2),
s => Global.Settings.ModifiedDNS = s,
Global.Settings.ModifiedDNS);
BindCheckBox(RedirectorSSCheckBox,
s => Global.Settings.RedirectorSS = s,
Global.Settings.RedirectorSS);
BindCheckBox(NoProxyForUdpCheckBox,
s => Global.Settings.ProcessNoProxyForUdp = s,
Global.Settings.ProcessNoProxyForUdp);
BindCheckBox(NoProxyForTcpCheckBox,
s => Global.Settings.ProcessNoProxyForTcp = s,
Global.Settings.ProcessNoProxyForTcp);
#endregion
#region TUN/TAP
@@ -111,6 +138,15 @@ namespace Netch.Forms
Global.Settings.TUNTAP.UseCustomDNS);
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
BindTextBox(TUNTAPDNSTextBox,
s => !UseCustomDNSCheckBox.Checked || DNS.TrySplit(s, out _, 2),
s =>
{
if (UseCustomDNSCheckBox.Checked)
Global.Settings.TUNTAP.DNS = DNS.Split(s).ToList();
},
DNS.Join(Global.Settings.TUNTAP.DNS));
BindCheckBox(ProxyDNSCheckBox,
b => Global.Settings.TUNTAP.ProxyDNS = b,
Global.Settings.TUNTAP.ProxyDNS);
@@ -139,6 +175,9 @@ namespace Netch.Forms
BindCheckBox(TLSAllowInsecureCheckBox,
b => Global.Settings.V2RayConfig.AllowInsecure = b,
Global.Settings.V2RayConfig.AllowInsecure);
BindCheckBox(UseMuxCheckBox,
b => Global.Settings.V2RayConfig.UseMux = b,
Global.Settings.V2RayConfig.UseMux);
BindTextBox<int>(mtuTextBox,
i => true,
@@ -205,6 +244,25 @@ namespace Netch.Forms
Global.Settings.UpdateSubscribeatWhenOpened);
#endregion
#region AioDNS
BindTextBox(AioDNSRulePathTextBox,
s => true,
s => Global.Settings.AioDNS.RulePath = s,
Global.Settings.AioDNS.RulePath);
BindTextBox(ChinaDNSTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.AioDNS.ChinaDNS = s,
Global.Settings.AioDNS.ChinaDNS);
BindTextBox(OtherDNSTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.AioDNS.OtherDNS = s,
Global.Settings.AioDNS.OtherDNS);
#endregion
}
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
@@ -214,12 +272,12 @@ namespace Netch.Forms
if (UseCustomDNSCheckBox.Checked)
{
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
? Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}")
? DNS.Join(Global.Settings.TUNTAP.DNS)
: "1.1.1.1";
}
else
{
TUNTAPDNSTextBox.Text = "Local DNS";
TUNTAPDNSTextBox.Text = "AioDNS";
}
}
@@ -248,77 +306,54 @@ namespace Netch.Forms
private void ControlButton_Click(object sender, EventArgs e)
{
if (!_checkActions.All(pair => pair.Value.Invoke(pair.Key.Text)))
return;
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
#region Check
#region TUNTAP
var dns = new string[0];
try
var flag = true;
foreach (var pair in _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)))
{
if (UseCustomDNSCheckBox.Checked)
{
dns = TUNTAPDNSTextBox.Text.Split(',').Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim())
.ToArray();
if (dns.Any())
{
foreach (var ip in dns)
IPAddress.Parse(ip);
}
else
{
MessageBoxX.Show("DNS can not be empty");
return;
}
}
Utils.Utils.ChangeControlForeColor(pair.Key, Color.Red);
flag = false;
}
catch (Exception exception)
if (!flag)
{
if (exception is FormatException)
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
if (UseCustomDNSCheckBox.Checked)
{
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
}
return;
}
#endregion
#region Behavior
#region CheckSTUN
// STUN
string stunServer;
int stunServerPort;
try
var errFlag = false;
var stunServer = string.Empty;
ushort stunServerPort = 3478;
var stun = STUN_ServerComboBox.Text.Split(':');
if (stun.Any())
{
var stun = STUN_ServerComboBox.Text.Split(':');
stunServer = stun[0];
stunServerPort = 3478;
if (stun.Length > 1)
stunServerPort = int.Parse(stun[1]);
if (stunServerPort <= 0)
{
throw new FormatException();
}
if (!ushort.TryParse(stun[1], out stunServerPort))
{
errFlag = true;
}
}
catch (FormatException)
else
{
MessageBoxX.Show(i18N.Translate("STUN_ServerPort value illegal. Try again."));
errFlag = true;
}
if (errFlag)
{
Utils.Utils.ChangeControlForeColor(STUN_ServerComboBox, Color.Red);
return;
}
#endregion
#endregion
#region Save
foreach (var pair in _saveActions)
@@ -326,73 +361,19 @@ namespace Netch.Forms
pair.Value.Invoke(pair.Key);
}
Global.Settings.TUNTAP.DNS = dns.ToList();
Global.Settings.STUN_Server = stunServer;
Global.Settings.STUN_Server_Port = stunServerPort;
Global.Settings.Language = LanguageComboBox.Text;
#endregion
#region Register Startup Item
var scheduler = new TaskSchedulerClass();
scheduler.Connect();
var folder = scheduler.GetFolder("\\");
var taskIsExists = false;
try
{
folder.GetTask("Netch Startup");
taskIsExists = true;
}
catch (Exception)
{
// ignored
}
if (Global.Settings.RunAtStartup)
{
if (taskIsExists)
folder.DeleteTask("Netch Startup", 0);
var task = scheduler.NewTask(0);
task.RegistrationInfo.Author = "Netch";
task.RegistrationInfo.Description = "Netch run at startup.";
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
var action = (IExecAction) task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
action.Path = Application.ExecutablePath;
task.Settings.ExecutionTimeLimit = "PT0S";
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null,
_TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
}
else
{
if (taskIsExists)
folder.DeleteTask("Netch Startup", 0);
}
#endregion
Utils.Utils.RegisterNetchStartupItem();
Configuration.Save();
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}
private bool CheckPort(string portName, ushort port, ushort originPort, PortType portType = PortType.Both)
{
if (port == originPort) return true;
if (!PortHelper.PortInUse(port, portType)) return true;
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
return false;
}
private async void ICSCheckBox_CheckedChanged(object sender, EventArgs e)
{
try
@@ -448,11 +429,42 @@ namespace Netch.Forms
{
control.Checked = value;
_checkActions.Add(control, s => true);
_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;
_checkActions.Add(control, s => true);
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
}
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
private readonly Dictionary<Control, Action<Control>> _saveActions = new Dictionary<Control, Action<Control>>();
private void ModifySystemDNSCheckBox_CheckedChanged(object sender, EventArgs e)
{
ModifiedDNSTextBox.Enabled = ModifySystemDNSCheckBox.Checked;
}
private void NoProxyForUdpCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (NoProxyForUdpCheckBox.Checked) NoProxyForTcpCheckBox.Checked = false;
}
private void NoProxyForTcpCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (NoProxyForTcpCheckBox.Checked) NoProxyForUdpCheckBox.Checked = false;
}
private void ICMPingRadioBtn_CheckedChanged(object sender, EventArgs e)
{
if (ICMPingRadioBtn.Checked) TCPingRadioBtn.Checked = false;
}
private void TCPingRadioBtn_CheckedChanged(object sender, EventArgs e)
{
if (TCPingRadioBtn.Checked) ICMPingRadioBtn.Checked = false;
}
}
}

View File

@@ -109,14 +109,14 @@ namespace Netch.Forms
return;
}
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
{
MessageBoxX.Show("Remark Name Duplicate!");
return;
}
if (_editingIndex == -1)
{
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
{
MessageBoxX.Show("Remark Name Duplicate!");
return;
}
Global.Settings.SubscribeLink.Add(new SubscribeLink
{
Remark = RemarkTextBox.Text,

View File

@@ -1,14 +1,14 @@
using System;
using Netch.Controllers;
using Netch.Forms;
using Netch.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Forms;
using Netch.Models;
using WindowsJobAPI;
namespace Netch
{
@@ -87,5 +87,10 @@ namespace Netch
/// 用于存储模式
/// </summary>
public static readonly List<Mode> Modes = new List<Mode>();
/// <summary>
/// Windows Job API
/// </summary>
public static readonly JobObject Job = new JobObject();
}
}

View File

@@ -33,20 +33,6 @@ namespace Netch.Models
/// </summary>
public int Type = 0;
public bool SupportSocks5Auth => Type switch
{
0 => true,
_ => false
};
public bool TestNatRequired => Type switch
{
0 => true,
1 => true,
2 => true,
_ => false
};
/// <summary>
/// 绕过中国0. 不绕过 1. 绕过)
/// </summary>
@@ -131,44 +117,15 @@ namespace Netch.Models
/// <returns>模式文件字符串</returns>
public string ToFileString()
{
string fileString;
switch (Type)
{
case 0:
// 进程模式
fileString = $"# {Remark}";
break;
case 1:
// TUN/TAP 规则内 IP CIDR无 Bypass China 设置
fileString = $"# {Remark}, {Type}, 0";
break;
default:
fileString = $"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}";
break;
}
fileString += Global.EOF;
fileString = Rule.Aggregate(fileString, (current, item) => $"{current}{item}{Global.EOF}");
// 去除最后的行尾符
fileString = fileString.Substring(0, fileString.Length - 2);
return fileString;
}
public string TypeToString()
{
return Type switch
{
0 => "Process",
1 => "TUNTAP",
2 => "TUNTAP",
3 => "SYSTEM",
4 => "S5",
5 => "S5+HTTP",
_ => "ERROR",
};
return $"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}{Global.EOF}{string.Join(Global.EOF, Rule)}";
}
}
public static class ModeExtension
{
/// 是否会转发 UDP
public static bool TestNatRequired(this Mode mode) => mode.Type is 0 or 1 or 2;
/// Socks5 分流是否能被有效实施
public static bool ClientRouting(this Mode mode) => mode.Type is not (1 or 2);
}
}

View File

@@ -4,7 +4,7 @@ using Netch.Utils;
namespace Netch.Models
{
public class Server
public class Server : ICloneable
{
/// <summary>
/// 备注
@@ -47,14 +47,17 @@ namespace Netch.Models
/// <returns>备注</returns>
public override string ToString()
{
if (string.IsNullOrWhiteSpace(Remark))
{
Remark = $"{Hostname}:{Port}";
}
var remark = string.IsNullOrWhiteSpace(Remark) ? $"{Hostname}:{Port}" : Remark;
Group = Group.Equals("None") || Group.Equals("") ? "NONE" : Group;
if (Group.Equals("None") || Group.Equals(""))
Group = "NONE";
return $"[{ServerHelper.GetUtilByTypeName(Type)?.ShortName ?? "WTF"}][{Group}] {Remark}";
return $"[{ServerHelper.GetUtilByTypeName(Type)?.ShortName ?? "WTF"}][{Group}] {remark}";
}
public object Clone()
{
return MemberwiseClone();
}
/// <summary>
@@ -78,7 +81,7 @@ namespace Netch.Models
{
try
{
return await Utils.Utils.TCPingAsync(destination, Port);
return Global.Settings.ServerTCPing ? await Utils.Utils.TCPingAsync(destination, Port) : await Utils.Utils.ICMPing(destination, Port);
}
catch (Exception)
{

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Netch.Models
{
@@ -65,6 +67,19 @@ namespace Netch.Models
public bool AllowInsecure = true;
public KcpConfig KcpConfig = new KcpConfig();
public bool UseMux = false;
}
public class AioDNSConfig
{
public string RulePath = "bin\\china_site_list";
public string ChinaDNS = "223.5.5.5";
public string OtherDNS = "1.1.1.1";
public string Protocol = "tcp";
}
/// <summary>
@@ -72,6 +87,11 @@ namespace Netch.Models
/// </summary>
public class Setting
{
public V2rayConfig V2RayConfig = new V2rayConfig();
public AioDNSConfig AioDNS = new AioDNSConfig();
/// <summary>
/// 服务器选择位置
/// </summary>
@@ -127,6 +147,11 @@ namespace Netch.Models
/// </summary>
public bool ModifySystemDNS = false;
/// <summary>
/// 要修改为的系统 DNS
/// </summary>
public string ModifiedDNS = "1.1.1.1,8.8.8.8";
/// <summary>
/// 解析服务器主机名
/// </summary>
@@ -137,6 +162,16 @@ namespace Netch.Models
/// </summary>
public int RequestTimeout = 10000;
/// <summary>
/// PAC URL
/// </summary>
public string Pac_Url = "";
/// <summary>
/// PAC端口
/// </summary>
public int Pac_Port = 2803;
/// <summary>
/// HTTP 本地端口
/// </summary>
@@ -222,6 +257,11 @@ namespace Netch.Models
/// </summary>
public string ACL = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
/// <summary>
/// GFWList
/// </summary>
public string GFWLIST = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";
/// <summary>
/// 是否使用DLL启动Shadowsocks
/// </summary>
@@ -232,6 +272,24 @@ namespace Netch.Models
/// </summary>
public string Language = "System";
public V2rayConfig V2RayConfig = new V2rayConfig();
/// <summary>
/// 服务器测试方式 false.ICMPing true.TCPing
/// </summary>
public bool ServerTCPing = true;
/// <summary>
/// 是否使用RDR内置SS
/// </summary>
public bool RedirectorSS = false;
/// <summary>
/// 不代理UDP
/// </summary>
public bool ProcessNoProxyForUdp = false;
/// <summary>
/// 不代理TCP
/// </summary>
public bool ProcessNoProxyForTcp = false;
}
}

View File

@@ -28,30 +28,6 @@ namespace Netch
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
public static extern bool DeleteRoute(string address, int cidr, string gateway, int index, int metric = 0);
/// <summary>
/// 设置直连
/// </summary>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetDIRECT();
/// <summary>
/// 设置全局
/// </summary>
/// <param name="remote">地址</param>
/// <param name="bypass">绕过</param>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetGlobal([MarshalAs(UnmanagedType.LPTStr)] string remote, [MarshalAs(UnmanagedType.LPTStr)] string bypass);
/// <summary>
/// 设置自动代理
/// </summary>
/// <param name="remote">URL</param>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetURL([MarshalAs(UnmanagedType.LPTStr)] string remote);
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();

View File

@@ -20,8 +20,10 @@ namespace Netch
{
if (args.Contains("-console"))
{
NativeMethods.AllocConsole();
NativeMethods.AttachConsole(-1);
if (!NativeMethods.AttachConsole(-1))
{
NativeMethods.AllocConsole();
}
}
// 创建互斥体防止多次运行

View File

@@ -66,12 +66,14 @@
<ItemGroup>
<PackageReference Include="ILMerge" Version="3.0.41" />
<PackageReference Include="MaxMind.GeoIP2" Version="3.3.0" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.61" />
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.62" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0-rc.2.20475.5" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0-rc.2.20475.5" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
<PackageReference Include="WindowsAPICodePack-Shell" Version="1.1.1" />
<PackageReference Include="WindowsJobAPI" Version="5.0.1" />
<PackageReference Include="WindowsProxy" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -60,6 +60,16 @@ namespace Netch.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] abp_js {
get {
object obj = ResourceManager.GetObject("abp_js", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@@ -1,145 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<assembly alias="System.Windows.Forms"
name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</data>
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\abp.js.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

BIN
Netch/Resources/abp.js.gz Normal file

Binary file not shown.

View File

@@ -81,10 +81,16 @@
"Modes have been reload": "模式已重载",
"Clean DNS Cache": "清理 DNS 缓存",
"DNS cache cleanup succeeded": "DNS 缓存清理成功",
"Update PAC": "更新 PAC",
"PAC updated successfully": "PAC 更新成功",
"PAC update failed": "PAC 更新失败",
"Update ACL": "更新 ACL 规则",
"Update ACL with proxy": "使用代理更新 ACL 规则",
"ACL updated successfully": "ACL 更新成功",
"ACL update failed": "ACL 更新失败",
"Open Directory": "打开目录",
"About": "关于",
@@ -155,6 +161,8 @@
"Update subscribeat when opened": "自动更新订阅",
"SS DLL": "SS DLL",
"Modify System DNS": "修改系统 DNS",
"No Proxy for Udp": "不代理Udp流量",
"No Proxy for Tcp": "不代理Tcp流量",
"ProfileCount": "快捷配置数量",
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试。",
@@ -163,6 +171,7 @@
"Failed to set the system proxy, it may be caused by the lack of dependent programs. Do you want to jump to Netch's official website to download dependent programs?": "设置系统代理失败,可能是缺少依赖导致,是否跳转 Netch 官网下载依赖程序?",
"Delay test after start": "启动后延迟测试",
"Enable": "启用",
"ServerPingType": "测速方式",
"Detection interval(sec)": "检测间隔(秒)",
"STUN Server": "STUN 服务器",
"STUN Server Port": "STUN 服务器端口",

View File

@@ -11,18 +11,17 @@ namespace Netch.Servers.Shadowsocks
public override string Name { get; protected set; } = "Shadowsocks";
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
private Mode _savedMode;
public bool DllFlag => Global.Settings.BootShadowsocksFromDLL && (_savedMode.Type == 0 || _savedMode.Type == 1 || _savedMode.Type == 2);
public bool DllFlag;
public bool Start(in Server s, in Mode mode)
{
_savedMode = mode;
Server = s;
var server = (Shadowsocks) s;
DllFlag = Global.Settings.BootShadowsocksFromDLL && mode.Type is 0 or 1 or 2 && !server.HasPlugin();
//从DLL启动Shaowsocks
if (DllFlag)
{
@@ -76,14 +75,12 @@ namespace Netch.Servers.Shadowsocks
public override void Stop()
{
if (Instance == null)
if (DllFlag)
ShadowsocksDLL.Stop();
else
StopInstance();
_savedMode = null;
}
private class ShadowsocksDLL
{
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]

View File

@@ -29,6 +29,8 @@ namespace Netch.Servers.Shadowsocks
{
Type = "SS";
}
public bool HasPlugin() => !string.IsNullOrWhiteSpace(Plugin) && !string.IsNullOrWhiteSpace(PluginOption);
}
public static class SSGlobal

View File

@@ -11,13 +11,11 @@ namespace Netch.Servers.ShadowsocksR
public override string Name { get; protected set; } = "ShadowsocksR";
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s, in Mode mode)
{
Server = s;
var server = (ShadowsocksR) s;
#region Argument

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Text.RegularExpressions;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.ShadowsocksR.Form;
using Netch.Utils;
using Newtonsoft.Json.Linq;
@@ -100,6 +101,22 @@ namespace Netch.Servers.ShadowsocksR
var group = paramsDict.ContainsKey("group") ? ShareLink.URLSafeBase64Decode(paramsDict["group"]) : string.Empty;
if (SSGlobal.EncryptMethods.Contains(method) && protocol == "origin" && obfs == "plain")
{
return new[]
{
new Shadowsocks.Shadowsocks
{
Hostname = serverAddr,
Port = serverPort,
EncryptMethod = method,
Password = password,
Remark = remarks,
Group = group
}
};
}
return new[]
{
new ShadowsocksR

View File

@@ -12,9 +12,8 @@ namespace Netch.Servers.Socks5
public bool Start(in Server s, in Mode mode)
{
Server = s;
var server = (Socks5) s;
if (server.Auth() && !mode.SupportSocks5Auth)
if (server.Auth())
{
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
if (StartInstanceAuto("-config ..\\data\\last.json"))
@@ -34,7 +33,6 @@ namespace Netch.Servers.Socks5
StopInstance();
}
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }

View File

@@ -18,27 +18,32 @@ namespace Netch.Servers.Trojan
public override string MainFile { get; protected set; } = "Trojan.exe";
public override string Name { get; protected set; } = "Trojan";
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s, in Mode mode)
{
Server = s;
var server = (Trojan) s;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new TrojanConfig
var trojanConfig = new TrojanConfig
{
local_addr = this.LocalAddress(),
local_port = this.Socks5LocalPort(),
remote_addr = server.AutoResolveHostname(),
remote_addr = server.Hostname,
remote_port = server.Port,
password = new List<string>
{
server.Password
}
}));
};
if (!string.IsNullOrWhiteSpace(server.Host))
trojanConfig.ssl.sni = server.Host;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(trojanConfig, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
return StartInstanceAuto("-c ..\\data\\last.json");
}

View File

@@ -14,17 +14,17 @@ namespace Netch.Servers.VLESS
/// <summary>
/// 加密方式
/// </summary>
public new string EncryptMethod { get; set; } = "none";
public override string EncryptMethod { get; set; } = "none";
/// <summary>
/// 传输协议
/// </summary>
public new string TransferProtocol { get; set; } = VLESSGlobal.TransferProtocols[0];
public override string TransferProtocol { get; set; } = VLESSGlobal.TransferProtocols[0];
/// <summary>
/// 伪装类型
/// </summary>
public new string FakeType { get; set; } = VLESSGlobal.FakeTypes[0];
public override string FakeType { get; set; } = VLESSGlobal.FakeTypes[0];
/// <summary>
///
@@ -34,7 +34,6 @@ namespace Netch.Servers.VLESS
public class VLESSGlobal
{
public static List<string> TransferProtocols => VMessGlobal.TransferProtocols;
public static readonly List<string> FakeTypes = new List<string>
@@ -42,5 +41,12 @@ namespace Netch.Servers.VLESS
"none",
"http"
};
public static readonly List<string> TLSSecure = new List<string>
{
"",
"tls",
"xtls"
};
}
}

View File

@@ -10,14 +10,12 @@ namespace Netch.Servers.VLESS
public override string Name { get; protected set; } = "VLESS";
public override string MainFile { get; protected set; } = "v2ray.exe";
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s,in Mode mode)
{
Server = s;
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
return StartInstanceAuto("-config ..\\data\\last.json");
}

View File

@@ -39,22 +39,20 @@ namespace Netch.Servers.VLESS.VLESSForm
s => true,
s => server.Path = s,
server.Path);
CreateComboBox("TLSSecure", "TLS Secure",
CreateComboBox("UseMux", "Use Mux",
new List<string> {"", "true", "false"},
s =>
s => server.UseMux = s switch
{
server.TLSSecure = s switch
{
"" => null,
"true" => true,
"false" => false,
_ => null
};
"" => null,
"true" => true,
"false" => false,
_ => null
},
server.TLSSecure?.ToString() ?? string.Empty);
CreateCheckBox("UseMux", "Use Mux",
b => server.UseMux = b,
server.UseMux);
server.UseMux?.ToString().ToLower() ?? "");
CreateComboBox("TLSSecure", "TLS Secure",
VLESSGlobal.TLSSecure,
s => server.TLSSecureType = s,
server.TLSSecureType);
}
}
}

View File

@@ -48,22 +48,20 @@ namespace Netch.Servers.VMess.Form
s => true,
s => server.QUICSecret = s,
server.QUICSecret);
CreateComboBox("TLSSecure", "TLS Secure",
CreateComboBox("UseMux", "Use Mux",
new List<string> {"", "true", "false"},
s =>
s => server.UseMux = s switch
{
server.TLSSecure = s switch
{
"" => null,
"true" => true,
"false" => false,
_ => null
};
"" => null,
"true" => true,
"false" => false,
_ => null
},
server.TLSSecure?.ToString() ?? string.Empty);
CreateCheckBox("UseMux", "Use Mux",
s => server.UseMux = s,
server.UseMux);
server.UseMux?.ToString().ToLower() ?? "");
CreateComboBox("TLSSecure", "TLS Secure",
VMessGlobal.TLSSecure,
s => server.TLSSecureType = s,
server.TLSSecureType);
}
}
}

View File

@@ -195,8 +195,6 @@ namespace Netch.Servers.VMess.Models
public class TcpSettings
{
public bool connectionReuse { get; set; }
public Header header { get; set; }
}
@@ -257,8 +255,6 @@ namespace Netch.Servers.VMess.Models
public class WsSettings
{
public bool connectionReuse { get; set; }
public string path { get; set; }
public Headers headers { get; set; }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Netch.Models;
using Netch.Servers.VMess.Models;
using Newtonsoft.Json;
@@ -18,9 +19,9 @@ namespace Netch.Servers.VMess.Utils
routing(server, mode, ref v2rayConfig);
outbound(server, ref v2rayConfig);
outbound(server, mode, ref v2rayConfig);
return JsonConvert.SerializeObject(v2rayConfig);
return JsonConvert.SerializeObject(v2rayConfig, Formatting.Indented, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
}
catch
{
@@ -58,44 +59,72 @@ namespace Netch.Servers.VMess.Utils
{
try
{
RulesItem rulesItem;
var directRuleObject = new RulesItem
{
type = "field",
ip = new List<string>(),
domain = new List<string>(),
outboundTag = "direct"
};
var blockRuleObject = new RulesItem
{
type = "field",
ip = new List<string>(),
domain = new List<string>(),
outboundTag = "block"
};
if (mode.BypassChina)
{
rulesItem = new RulesItem
switch (mode.Type)
{
type = "field",
ip = new List<string>
{
"geoip:cn",
"geoip:private"
},
domain = new List<string>
{
"geosite:cn"
},
outboundTag = "direct"
};
case 0:
directRuleObject.ip.Add("geoip:cn");
break;
case 1:
case 2:
if (Global.Flags.SupportFakeDns && Global.Settings.TUNTAP.UseFakeDNS)
directRuleObject.domain.Add("geosite:cn");
else
directRuleObject.ip.Add("geoip:cn");
break;
default:
directRuleObject.domain.Add("geosite:cn");
break;
}
}
else
if (mode.Type is 0 or 1 or 2)
{
rulesItem = new RulesItem
{
type = "field",
ip = new List<string>
{
"geoip:private"
},
outboundTag = "direct"
};
blockRuleObject.ip.Add("geoip:private");
}
v2rayConfig.routing = new Routing
{
rules = new List<RulesItem>
{
rulesItem
}
rules = new List<RulesItem>()
};
static bool CheckRuleItem(ref RulesItem rulesItem)
{
bool ipResult, domainResult;
if (!(ipResult = rulesItem.ip.Any()))
{
rulesItem.ip = null;
}
if (!(domainResult = rulesItem.domain.Any()))
{
rulesItem.domain = null;
}
return ipResult || domainResult;
}
if (CheckRuleItem(ref directRuleObject))
v2rayConfig.routing.rules.Add(directRuleObject);
if (CheckRuleItem(ref blockRuleObject))
v2rayConfig.routing.rules.Add(blockRuleObject);
}
catch
{
@@ -103,7 +132,7 @@ namespace Netch.Servers.VMess.Utils
}
}
private static void outbound(Server server, ref V2rayConfig v2rayConfig)
private static void outbound(Server server, Mode mode, ref V2rayConfig v2rayConfig)
{
try
{
@@ -121,31 +150,25 @@ namespace Netch.Servers.VMess.Utils
{
case Socks5.Socks5 socks5:
{
var serversItem = new ServersItem
{
users = new List<SocksUsersItem>()
};
outbound.settings.servers = new List<ServersItem>
{
serversItem
};
serversItem.address = server.AutoResolveHostname();
serversItem.port = server.Port;
serversItem.method = null;
serversItem.password = null;
if (socks5.Auth())
{
var socksUsersItem = new SocksUsersItem
new ServersItem
{
user = socks5.Username,
pass = socks5.Password,
level = 1
};
serversItem.users.Add(socksUsersItem);
}
users = socks5.Auth()
? new List<SocksUsersItem>
{
new SocksUsersItem
{
user = socks5.Username,
pass = socks5.Password,
level = 1
}
}
: null,
address = server.AutoResolveHostname(),
port = server.Port
}
};
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
@@ -156,37 +179,36 @@ namespace Netch.Servers.VMess.Utils
{
var vnextItem = new VnextItem
{
users = new List<UsersItem>()
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.settings.vnext = new List<VnextItem>
outbound.settings.vnext = new List<VnextItem> {vnextItem};
var usersItem = new UsersItem
{
vnextItem
id = vless.UserID,
alterId = 0,
flow = string.Empty,
encryption = vless.EncryptMethod
};
vnextItem.address = server.AutoResolveHostname();
vnextItem.port = server.Port;
var usersItem = new UsersItem();
vnextItem.users.Add(usersItem);
usersItem.id = vless.UserID;
usersItem.alterId = 0;
usersItem.flow = string.Empty;
usersItem.encryption = vless.EncryptMethod;
outbound.mux.enabled = vless.UseMux;
outbound.mux.concurrency = vless.UseMux ? 8 : -1;
var streamSettings = outbound.streamSettings;
boundStreamSettings(vless, ref streamSettings);
if (vless.TransferProtocol == "xtls")
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;
@@ -196,35 +218,42 @@ namespace Netch.Servers.VMess.Utils
{
var vnextItem = new VnextItem
{
users = new List<UsersItem>()
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.settings.vnext = new List<VnextItem>
outbound.settings.vnext = new List<VnextItem> {vnextItem};
var usersItem = new UsersItem
{
vnextItem
id = vmess.UserID,
alterId = vmess.AlterID,
security = vmess.EncryptMethod
};
vnextItem.address = server.AutoResolveHostname();
vnextItem.port = server.Port;
var usersItem = new UsersItem();
vnextItem.users.Add(usersItem);
usersItem.id = vmess.UserID;
usersItem.alterId = vmess.AlterID;
usersItem.security = vmess.EncryptMethod;
outbound.mux.enabled = vmess.UseMux;
outbound.mux.concurrency = vmess.UseMux ? 8 : -1;
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;
}
}
v2rayConfig.outbounds = new List<Outbounds> {outbound};
v2rayConfig.outbounds = new List<Outbounds>
{
outbound,
new Outbounds
{
tag = "direct", protocol = "freedom"
},
new Outbounds
{
tag = "block", protocol = "blackhole"
}
};
}
catch
{
@@ -237,25 +266,24 @@ namespace Netch.Servers.VMess.Utils
try
{
streamSettings.network = server.TransferProtocol;
var host = server.Host;
if (server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure)
{
streamSettings.security = "tls";
if ((streamSettings.security = server.TLSSecureType) != "")
{
var tlsSettings = new TlsSettings
{
allowInsecure = true
allowInsecure = Global.Settings.V2RayConfig.AllowInsecure,
serverName = !string.IsNullOrWhiteSpace(server.Host) ? server.Host : null
};
if (!string.IsNullOrWhiteSpace(host))
{
tlsSettings.serverName = host;
}
streamSettings.tlsSettings = tlsSettings;
}
else
{
streamSettings.security = "";
switch (server.TLSSecureType)
{
case "tls":
streamSettings.tlsSettings = tlsSettings;
break;
case "xtls":
streamSettings.xtlsSettings = tlsSettings;
break;
}
}
switch (server.TransferProtocol)
@@ -277,21 +305,15 @@ namespace Netch.Servers.VMess.Utils
seed = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
};
streamSettings.kcpSettings = kcpSettings;
break;
case "ws":
var path = server.Path;
var wsSettings = new WsSettings
{
connectionReuse = true,
headers = !string.IsNullOrWhiteSpace(host)
? new Headers
{
Host = host
}
headers = !string.IsNullOrWhiteSpace(server.Host)
? new Headers {Host = server.Host}
: null,
path = !string.IsNullOrWhiteSpace(path) ? path : null
path = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
};
streamSettings.wsSettings = wsSettings;
@@ -311,40 +333,27 @@ namespace Netch.Servers.VMess.Utils
case "quic":
var quicSettings = new QuicSettings
{
security = host,
security = server.Host,
key = server.Path,
header = new Header
{
type = server.FakeType
}
};
if (server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure)
if (server.TLSSecureType != "")
{
// tls or xtls
streamSettings.tlsSettings.serverName = server.Hostname;
}
streamSettings.quicSettings = quicSettings;
break;
case "xtls":
streamSettings.security = server.TransferProtocol;
var xtlsSettings = new TlsSettings
{
allowInsecure = true
};
if (!string.IsNullOrWhiteSpace(host))
{
xtlsSettings.serverName = host;
}
streamSettings.xtlsSettings = xtlsSettings;
break;
default:
if (server.FakeType == "http")
{
var tcpSettings = new TcpSettings
{
connectionReuse = true,
header = new Header
{
type = server.FakeType,

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Netch.Models;
@@ -23,18 +24,18 @@ namespace Netch.Servers.VMess
/// <summary>
/// 加密方式
/// </summary>
public string EncryptMethod { get; set; } = VMessGlobal.EncryptMethods[0];
public virtual string EncryptMethod { get; set; } = VMessGlobal.EncryptMethods[0];
/// <summary>
/// 传输协议
/// </summary>
public string TransferProtocol { get; set; } = VMessGlobal.TransferProtocols[0];
public virtual string TransferProtocol { get; set; } = VMessGlobal.TransferProtocols[0];
/// <summary>
/// 伪装类型
/// </summary>
public string FakeType { get; set; } = VMessGlobal.FakeTypes[0];
public virtual string FakeType { get; set; } = VMessGlobal.FakeTypes[0];
/// <summary>
/// QUIC
@@ -64,12 +65,12 @@ namespace Netch.Servers.VMess
/// <summary>
/// TLS 底层传输安全
/// </summary>
public bool? TLSSecure { get; set; }
public string TLSSecureType { get; set; } = VMessGlobal.TLSSecure[0];
/// <summary>
/// Mux 多路复用
/// </summary>
public bool UseMux { get; set; } = true;
public bool? UseMux { get; set; } = false;
}
public class VMessGlobal
@@ -114,5 +115,14 @@ namespace Netch.Servers.VMess
"dtls",
"wireguard"
};
/// <summary>
/// TLS 安全类型
/// </summary>
public static readonly List<string> TLSSecure = new List<string>
{
"",
"tls"
};
}
}

View File

@@ -13,16 +13,14 @@ namespace Netch.Servers.VMess
StoppedKeywords.AddRange(new[] {"config file not readable", "failed to"});
}
public override string Name { get; protected set; } = "V2Ray";
public override string Name { get; protected set; } = "VMess";
public override string MainFile { get; protected set; } = "v2ray.exe";
public Server Server { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s,in Mode mode)
{
Server = s;
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
return StartInstanceAuto("-config ..\\data\\last.json");
}

View File

@@ -49,7 +49,7 @@ namespace Netch.Servers.VMess
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure ? "tls" : ""
tls = server.TLSSecureType
});
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
}
@@ -97,7 +97,7 @@ namespace Netch.Servers.VMess
data.Path = vmess.path;
}
data.TLSSecure = vmess.tls == "tls";
data.TLSSecureType = vmess.tls;
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
return CheckServer(data) ? new[] {data} : null;

View File

@@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Tracing.Session;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
namespace Netch.Utils
{
@@ -63,26 +64,28 @@ namespace Netch.Utils
//var processList = Process.GetProcessesByName(ProcessName).Select(p => p.Id).ToHashSet();
var instances = new List<Process>();
if (server.Type.Equals("Socks5") && MainController.ModeController.Name == "HTTP")
switch (MainController.ServerController)
{
instances.Add(((HTTPController) MainController.ModeController).pPrivoxyController.Instance);
}
else if (MainController.ServerController != null)
{
switch (MainController.ServerController)
{
case SSController ssController when ssController.DllFlag:
instances.Add(Process.GetCurrentProcess());
break;
case Guard instanceController:
case null:
break;
case SSController ssController when ssController.DllFlag:
instances.Add(Process.GetCurrentProcess());
break;
case Guard instanceController:
if (instanceController.Instance != null)
instances.Add(instanceController.Instance);
break;
}
break;
}
else if (MainController.ModeController != null)
if (!instances.Any())
{
switch (MainController.ModeController)
{
case null:
break;
case HTTPController httpController:
instances.Add(httpController.pPrivoxyController.Instance);
break;
case NFController _:
instances.Add(Process.GetCurrentProcess());
break;

View File

@@ -30,14 +30,14 @@ namespace Netch.Utils
Global.Settings = settingJObject?.ToObject<Setting>() ?? new Setting();
Global.Settings.Server.Clear();
foreach (JObject server in settingJObject["Server"])
{
var serverResult = ServerHelper.ParseJObject(server);
if (serverResult != null)
Global.Settings.Server.Add(serverResult);
}
if (settingJObject?["Server"] != null)
foreach (JObject server in settingJObject["Server"])
{
var serverResult = ServerHelper.ParseJObject(server);
if (serverResult != null)
Global.Settings.Server.Add(serverResult);
}
}
catch (JsonException)
{
}
@@ -62,7 +62,15 @@ namespace Netch.Utils
Directory.CreateDirectory(DATA_DIR);
}
File.WriteAllText(SETTINGS_JSON, JsonConvert.SerializeObject(Global.Settings, Formatting.Indented));
File.WriteAllText(SETTINGS_JSON,
JsonConvert.SerializeObject(
Global.Settings,
Formatting.Indented,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}
));
}
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.Win32;
@@ -75,5 +77,24 @@ namespace Netch.Utils
}
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
}
public static IEnumerable<string> Split(string dns)
{
return dns.Split(',').Where(ip => !string.IsNullOrWhiteSpace(ip)).Select(ip => ip.Trim());
}
public static bool TrySplit(string value, out IEnumerable<string> result, ushort maxCount = 0)
{
result = Split(value).ToArray();
return maxCount == 0 || result.Count() <= maxCount
&&
result.All(ip => IPAddress.TryParse(ip, out _));
}
public static string Join(IEnumerable<string> dns)
{
return string.Join(",", dns);
}
}
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Net;
using System.Text;
using System.Threading;
namespace Netch.Utils.HttpProxyHandler
{
public class HttpWebServer
{
private HttpListener _listener;
private Func<HttpListenerRequest, string> _responderMethod;
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
{
try
{
_listener = new HttpListener();
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required, for example
// "http://localhost:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
_listener.Prefixes.Add(s);
_responderMethod = method;
_listener.Start();
}
catch (Exception ex)
{
Logging.Error("HttpWebServer():" + ex.Message);
}
}
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
: this(prefixes, method)
{
}
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Logging.Info("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch
{
} // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch (Exception ex)
{
//Logging.Error(ex.Message, ex);
Logging.Error(ex.Message);
} // suppress any exceptions
});
}
public void Stop()
{
if (_listener != null)
{
_listener.Stop();
_listener.Close();
_listener = null;
}
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
using WindowsProxy;
namespace Netch.Utils.HttpProxyHandler
{
/// <summary>
/// 提供PAC功能支持
/// </summary>
class PACServerHandle
{
private static Hashtable httpWebServer = new Hashtable();
private static Hashtable pacList = new Hashtable();
public static void InitPACServer(string address)
{
try
{
if (!pacList.ContainsKey(address))
{
pacList.Add(address, GetPacList(address));
}
string prefixes = string.Format("http://{0}:{1}/pac/", address, Global.Settings.Pac_Port);
HttpWebServer ws = new HttpWebServer(SendResponse, prefixes);
ws.Run();
if (!httpWebServer.ContainsKey(address) && ws != null)
{
httpWebServer.Add(address, ws);
}
Global.Settings.Pac_Url = GetPacUrl();
using var service = new ProxyService
{
AutoConfigUrl = Global.Settings.Pac_Url
};
service.Pac();
Logging.Info(service.Set(service.Query()) + "");
Logging.Info($"Webserver InitServer OK: {Global.Settings.Pac_Url}");
}
catch (Exception ex)
{
Logging.Error("Webserver InitServer " + ex.Message);
}
}
public static string SendResponse(HttpListenerRequest request)
{
try
{
string[] arrAddress = request.UserHostAddress.Split(':');
string address = "127.0.0.1";
if (arrAddress.Length > 0)
{
address = arrAddress[0];
}
return pacList[address].ToString();
}
catch (Exception ex)
{
Logging.Error("Webserver SendResponse " + ex.Message);
return ex.Message;
}
}
public static void Stop()
{
try
{
if (httpWebServer == null)
{
return;
}
foreach (var key in httpWebServer.Keys)
{
Logging.Info("Webserver Stop " + key.ToString());
((HttpWebServer)httpWebServer[key]).Stop();
}
httpWebServer.Clear();
}
catch (Exception ex)
{
Logging.Error("Webserver Stop " + ex.Message);
}
}
private static string GetPacList(string address)
{
try
{
List<string> lstProxy = new List<string>();
lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort));
var proxy = string.Join("", lstProxy.ToArray());
string strPacfile = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
return pac;
}
catch
{ }
return "No pac content";
}
/// <summary>
/// 获取PAC地址
/// </summary>
/// <returns></returns>
public static string GetPacUrl()
{
string pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port,
DateTime.Now.ToString("yyyyMMddHHmmssfff"));
return pacUrl;
}
}
}

View File

@@ -0,0 +1,56 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using Netch.Forms;
using Netch.Properties;
namespace Netch.Utils.HttpProxyHandler
{
/// <summary>
/// 提供PAC功能支持
/// </summary>
class PACUtil
{
private static readonly IEnumerable<char> IgnoredLineBegins = new[] {'!', '['};
public static List<string> ParseResult(string response)
{
byte[] bytes = Convert.FromBase64String(response);
string content = Encoding.ASCII.GetString(bytes);
List<string> valid_lines = new List<string>();
using (var sr = new StringReader(content))
{
foreach (var line in sr.NonWhiteSpaceLines())
{
if (line.BeginWithAny(IgnoredLineBegins))
continue;
valid_lines.Add(line);
}
}
return valid_lines;
}
public static string UnGzip(byte[] buf)
{
byte[] buffer = new byte[1024];
int n;
using (MemoryStream sb = new MemoryStream())
{
using (GZipStream input = new GZipStream(new MemoryStream(buf),
CompressionMode.Decompress,
false))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
sb.Write(buffer, 0, n);
}
}
return System.Text.Encoding.UTF8.GetString(sb.ToArray());
}
}
}
}

View File

@@ -5,6 +5,8 @@ using System.Linq;
using Netch.Controllers;
using Netch.Forms;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
namespace Netch.Utils
{
@@ -66,17 +68,19 @@ namespace Netch.Utils
if (i == 0)
{
if (text.First() != '#')
return;
try
{
var splited = text.Substring(text.IndexOf('#') + 1).Split(',').Select(s => s.Trim()).ToArray();
var splited = text.Substring(1).Split(',').Select(s => s.Trim()).ToArray();
mode.Remark = splited[0];
var result = int.TryParse(splited.ElementAtOrDefault(1), out var type);
mode.Type = result ? type : 0;
var typeResult = int.TryParse(splited.ElementAtOrDefault(1), out var type);
mode.Type = typeResult ? type : 0;
var result1 = int.TryParse(splited.ElementAtOrDefault(2), out var bypassChina);
mode.BypassChina = result1 && bypassChina == 1;
var bypassChinaResult = int.TryParse(splited.ElementAtOrDefault(2), out var bypassChina);
mode.BypassChina = mode.ClientRouting() && bypassChinaResult && bypassChina == 1;
}
catch
{
@@ -135,6 +139,21 @@ namespace Netch.Utils
Global.MainForm.InitMode();
}
public static bool SkipServerController(Server server, Mode mode)
{
return mode.Type switch
{
0 => server switch
{
Socks5 => true,
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS => true,
_ => false
},
_ => false
};
}
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName, out PortType portType)
{
IModeController modeController;

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Shadowsocks.Models;
using Netch.Servers.VMess;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Server = Netch.Models.Server;
@@ -233,7 +234,8 @@ namespace Netch.Utils
public static string GetNetchLink(Server s)
{
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(s));
var server = (Server) s.Clone();
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(server, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
}
}
}

46
Netch/Utils/StringEx.cs Normal file
View File

@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Netch.Utils
{
static class StringEx
{
public static bool IsNullOrEmpty(this string value)
{
return string.IsNullOrEmpty(value);
}
public static bool IsNullOrWhiteSpace(this string value)
{
return string.IsNullOrWhiteSpace(value);
}
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
{
if (s.IsNullOrEmpty()) return false;
return chars.Contains(s[0]);
}
public static bool IsWhiteSpace(this string value)
{
foreach (var c in value)
{
if (char.IsWhiteSpace(c)) continue;
return false;
}
return true;
}
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.IsWhiteSpace()) continue;
yield return line;
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Netch.Models;
namespace Netch.Utils
{
public static class Subscription
{
private static readonly object ServerLock = new object();
public static async Task UpdateServersAsync(string proxyServer = default)
{
await Task.WhenAll(
Global.Settings.SubscribeLink.Select(item =>
Task.Run(() => UpdateServer(item, proxyServer))
).ToArray()
);
}
public static void UpdateServer(SubscribeLink item, string proxyServer)
{
try
{
var request = WebUtil.CreateRequest(item.Link);
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;
if (!string.IsNullOrEmpty(proxyServer)) request.Proxy = new WebProxy(proxyServer);
List<Server> servers;
var result = WebUtil.DownloadString(request, out var rep);
if (rep.StatusCode == HttpStatusCode.OK)
servers = ShareLink.ParseText(result);
else
throw new Exception($"{item.Remark} Response Status Code: {rep.StatusCode}");
foreach (var server in servers) server.Group = item.Remark;
lock (ServerLock)
{
Global.Settings.Server.RemoveAll(server => server.Group.Equals(item.Remark));
Global.Settings.Server.AddRange(servers);
}
Global.MainForm.NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, servers.Count));
}
catch (Exception e)
{
Global.MainForm.NotifyTip($"{i18N.TranslateFormat("Update servers error from {0}", item.Remark)}\n{e.Message}", info: false);
Logging.Error(e.ToString());
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
@@ -7,10 +7,12 @@ using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using MaxMind.GeoIP2;
using TaskScheduler;
namespace Netch.Utils
{
@@ -37,12 +39,12 @@ namespace Netch.Utils
public static async Task<int> TCPingAsync(IPAddress ip, int port, int timeout = 1000, CancellationToken ct = default)
{
using var client = new TcpClient(ip.AddressFamily);
var stopwatch = Stopwatch.StartNew();
var task = client.ConnectAsync(ip, port);
var stopwatch = new Stopwatch();
stopwatch.Start();
var resTask = await Task.WhenAny(Task.Delay(timeout, ct), task);
var resTask = await Task.WhenAny(task, Task.Delay(timeout, ct));
stopwatch.Stop();
if (resTask == task && client.Connected)
@@ -54,6 +56,18 @@ namespace Netch.Utils
return timeout;
}
public static async Task<int> ICMPing(IPAddress ip, int timeout = 1000)
{
var reply = new Ping().Send(ip, timeout);
if (reply?.Status == IPStatus.Success)
{
return Convert.ToInt32(reply.RoundtripTime);
}
return timeout;
}
public static string GetCityCode(string Hostname)
{
if (Hostname.Contains(":"))
@@ -96,7 +110,7 @@ namespace Netch.Utils
{
try
{
var sha256 = System.Security.Cryptography.SHA256.Create();
var sha256 = SHA256.Create();
var fileStream = File.OpenRead(filePath);
return sha256.ComputeHash(fileStream).Aggregate(string.Empty, (current, b) => current + b.ToString("x2"));
}
@@ -237,5 +251,62 @@ namespace Netch.Utils
break;
}
}
public static void RegisterNetchStartupItem()
{
var scheduler = new TaskSchedulerClass();
scheduler.Connect();
var folder = scheduler.GetFolder("\\");
var taskIsExists = false;
try
{
folder.GetTask("Netch Startup");
taskIsExists = true;
}
catch
{
// ignored
}
if (Global.Settings.RunAtStartup)
{
if (taskIsExists)
folder.DeleteTask("Netch Startup", 0);
var task = scheduler.NewTask(0);
task.RegistrationInfo.Author = "Netch";
task.RegistrationInfo.Description = "Netch run at startup.";
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
var action = (IExecAction) task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
action.Path = Application.ExecutablePath;
task.Settings.ExecutionTimeLimit = "PT0S";
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null,
_TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
}
else
{
if (taskIsExists)
folder.DeleteTask("Netch Startup", 0);
}
}
public static void ChangeControlForeColor(Component component, Color color)
{
switch (component)
{
case TextBox _:
case ComboBox _:
if (((Control) component).ForeColor != color) ((Control) component).ForeColor = color;
break;
}
}
}
}

View File

@@ -8,8 +8,13 @@ namespace Netch.Utils
{
public static class WebUtil
{
static WebUtil()
{
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
}
public const string DefaultUserAgent =
@"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36";
@"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55";
private static int DefaultGetTimeout => Global.Settings.RequestTimeout;
@@ -47,6 +52,22 @@ namespace Netch.Utils
return memoryStream.ToArray();
}
/// <summary>
/// 异步下载并编码为字符串
/// </summary>
/// <param name="req"></param>
/// <param name="rep"></param>
/// <param name="encoding">编码默认UTF-8</param>
/// <returns></returns>
public static string DownloadString(HttpWebRequest req, out HttpWebResponse rep, string encoding = "UTF-8")
{
rep = (HttpWebResponse) req.GetResponse();
using var responseStream = rep.GetResponseStream();
using var streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encoding));
return streamReader.ReadToEnd();
}
/// <summary>
/// 异步下载并编码为字符串
/// </summary>
@@ -78,4 +99,4 @@ namespace Netch.Utils
fileStream.Flush();
}
}
}
}

View File

@@ -1,67 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Platforms>x86;x64</Platforms>
<ProjectGuid>{A8715AF4-ACC6-43F9-9381-4294C5360623}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NetchLib</RootNamespace>
<AssemblyName>NetchLib</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<NoWarn />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn />
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<OutputPath>bin\x86\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn />
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn />
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<OutputPath>bin\x64\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SearchComboBox.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Platforms>x64</Platforms>
<UseWindowsForms>true</UseWindowsForms>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>

View File

@@ -75,7 +75,7 @@ namespace System.Windows.Forms
private bool IsOriginalItems => Items.Count == AutoFillTag.Length;
private void ResetCompletionList()
public void ResetCompletionList()
{
Keyword = null;
try

View File

@@ -41,9 +41,7 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
- [RabbitHosts](https://rabbithosts.com/cart.php)
- [ManSora](https://www.mansora.co/cart.php)
- [ExCloud](https://excloud.net/cart.php)
- [NyanCat](https://nyancat.info/register)
- [YoYu](https://home.yoyu.ltd/cart.php)
## Donate
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
@@ -65,8 +63,11 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
- [v2ray-core](https://github.com/v2ray/v2ray-core)
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [GFWList](https://github.com/gfwlist/gfwlist)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
- [NetFilter SDK](https://netfiltersdk.com/)
[![Stargazers over time](https://starchart.cc/NetchX/Netch.svg)](https://starchart.cc/NetchX/Netch)

View File

@@ -44,9 +44,7 @@ Netch 是一款 Windows 平台的开源游戏加速工具Netch 可以实现
- [RabbitHosts](https://rabbithosts.com/cart.php)
- [ManSora](https://www.mansora.co/cart.php)
- [ExCloud](https://excloud.net/cart.php)
- [NyanCat](https://nyancat.info/register)
- [YoYu](https://home.yoyu.ltd/cart.php)
## 捐赠
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
@@ -74,6 +72,7 @@ Netch 支持多种语言,在启动时会根据系统语言选择自身语言
- [v2ray-core](https://github.com/v2ray/v2ray-core)
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [GFWList](https://github.com/gfwlist/gfwlist)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)

2
modes

Submodule modes updated: 3ac9f3c380...e3ae0d5406