Compare commits

..

171 Commits
1.6.0 ... 1.6.8

Author SHA1 Message Date
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
ChsBuffer
af5100fe73 bump version to 1.6.4 2020-10-21 21:48:23 +08:00
ChsBuffer
f8bcef7ac9 fix: Updater parse multiple space path 2020-10-21 21:40:55 +08:00
ChsBuffer
591f8e5a5c feat: V2Ray TLS AllowInsecure Setting 2020-10-21 21:34:28 +08:00
ChsBuffer
00047a5030 refactor: SettingForm
feat: KCPSettings
2020-10-21 21:25:07 +08:00
ChsBuffer
6d4dab573e feat: split SettingForm settings 2020-10-21 17:50:22 +08:00
ChsBuffer
141fc58df4 fix: #415 Mode 4 start failed 2020-10-21 16:38:30 +08:00
ChsBuffer
4210f36814 fix: VLESSForm UseMux CheckBox 2020-10-20 17:52:17 +08:00
ChsBuffer
98adb01760 bump version to 1.6.3 2020-10-20 14:37:28 +08:00
ChsBuffer
a2ae28d3ae refactor: resize MainForm when no Profile 2020-10-20 10:59:53 +08:00
ChsBuffer
30854deba6 fix: TAP Mode first time searching adapter 2020-10-19 17:41:01 +08:00
ChsBuffer
ef8013c073 fix: installed NF Driver version output 2020-10-19 17:30:03 +08:00
ChsBuffer
abfae4a9a0 refactor: MainForm change Enabled to change State 2020-10-19 17:29:59 +08:00
Connection Refused
4731e27d2e Update Redirector 2020-10-19 15:27:07 +08:00
ChsBuffer
a993df7f2f fix: upgrade package and upgrade Test.csproj to new format 2020-10-17 18:03:26 +08:00
ChsBuffer
3c6c2bde31 refactor: cut IPNetwork2 2020-10-17 17:27:01 +08:00
ChsBuffer
f8299fb7be refactor: Add in keyword as need 2020-10-17 17:18:40 +08:00
ChsBuffer
b54bc6fa40 feat: Redirector socks5 authentication support
refactor: Redirector dial
2020-10-17 16:18:40 +08:00
ChsBuffer
b2ac98b21f refactor: change port type to ushort 2020-10-17 15:20:56 +08:00
Connection Refused
86a86a94d8 Update Redirector 2020-10-17 15:08:23 +08:00
ChsBuffer
7bbffb002f refactor: Add GetModeControllerByType 2020-10-16 15:42:35 +08:00
ChsBuffer
1b6fe29085 refactor: Remove Server argument in IModeController.Start 2020-10-15 19:17:04 +08:00
ChsBuffer
918e260f3e refactor: Add IServerController.Server and use in ModeControllers 2020-10-15 19:15:13 +08:00
ChsBuffer
508e77759c fix: ServerController is not assigned 2020-10-15 15:03:20 +08:00
Amazing_DM
a21d7ff6fd 修复停止后代理进程未结束的问题 2020-10-15 14:27:28 +08:00
AmazingDM
b4050f2fa4 Update Advanced_Usage.zh-CN.md 2020-10-15 09:41:32 +08:00
ChsBuffer
1b1a9fc05d fix: PrivoxyController typo 2020-10-14 20:01:26 +08:00
ChsBuffer
985330f564 refactor: change port type to ushort
refactor: StatusPortInfoText
2020-10-14 17:40:48 +08:00
ChsBuffer
eb6b87e4aa refacotr: StartServer 2020-10-14 17:19:03 +08:00
ChsBuffer
5af2749760 refactor: updater argument parse to fix path with space 2020-10-13 19:13:46 +08:00
ChsBuffer
be4a18d599 feat: Trojan GetShareLink
fix: Socks5 Auth ShareLink
2020-10-13 11:24:07 +08:00
ChsBuffer
5d0bcbd6b0 fix: disable ResolveServerHostname default 2020-10-13 10:15:40 +08:00
ChsBuffer
ab6a2ecc30 fix: mode 2 try to delete 0.0.0.0/0 route entry twice 2020-10-13 10:05:32 +08:00
ChsBuffer
ceb57dcc1a refactor: move IModeController.TestNatRequired to Mode 2020-10-13 09:48:21 +08:00
ChsBuffer
79b6e5da43 feat: Mode.SupportSocks5Auth 2020-10-13 09:45:30 +08:00
ChsBuffer
2d95d8b257 refactor: NFController dial host 2020-10-13 09:43:19 +08:00
ChsBuffer
50eb07badf feat: warning mode self-reference 2020-10-13 09:08:58 +08:00
ChsBuffer
3f902a2d3d refactor: SetupRouteTable() rules creation order
fix: #397
2020-10-13 09:08:57 +08:00
Connection Refused
72b094e641 Update submodule 2020-10-13 08:43:25 +08:00
Connection Refused
c7fb7e3959 Update REAMDE.md 2020-10-13 08:38:52 +08:00
ChsBuffer
9e249bc211 refactor: boundStreamSettings
fix: #405
2020-10-13 08:15:12 +08:00
ChsBuffer
2332c9ec50 fix: VLESS Config Generate 2020-10-12 22:27:28 +08:00
ChsBuffer
202fdfe5a0 feat: support socks5 authentication 2020-10-12 22:18:56 +08:00
ChsBuffer
18b905ed0c feat: remove v2ray config file when exit 2020-10-12 21:56:53 +08:00
ChsBuffer
3f1b21c4e5 feat: VLESS support 2020-10-12 21:44:58 +08:00
ChsBuffer
477c6e3fc1 refactor: Generate V2ray Config 2020-10-12 21:39:37 +08:00
ChsBuffer
5e58708895 fix: Add Socks5 Authentication TextBox 2020-10-12 15:12:55 +08:00
ChsBuffer
c3eb07005e bump version to 1.6.2 2020-10-11 19:57:54 +08:00
ChsBuffer
12b2989755 feat: Resolve Server hostname option 2020-10-11 02:08:43 +08:00
ChsBuffer
0222792361 refactor: IServerController client config 2020-10-11 01:58:14 +08:00
ChsBuffer
3e5e3a7275 clean: remove SS DLL's No ACL support remark
refactor: Enable SS DLL by default
2020-10-11 00:56:55 +08:00
ChsBuffer
a49e280e03 refactor: NetTraffic record pid
fix: #399
2020-10-11 00:51:41 +08:00
ChsBuffer
45b6352553 feat: -console argument 2020-10-10 22:37:23 +08:00
Bruce Wayne
406fbd8b7e Merge pull request #398 from NetchX/fixCI 2020-10-10 22:35:16 +08:00
Bruce Wayne
454b03a69f Fix build scripts 2020-10-10 22:22:41 +08:00
ChsBuffer
98ab8864eb fix: SS DLL config 2020-10-10 21:43:53 +08:00
Bruce Wayne
f3358f3da2 Drop Nuget cache 2020-10-10 21:12:14 +08:00
Bruce Wayne
fa1593de49 Fix CI 2020-10-10 20:27:04 +08:00
Bruce Wayne
f26d09bf9f Update GetSHA256.ps1 2020-10-10 20:08:38 +08:00
ChsBuffer
35859a19f7 fix: #396 2020-10-10 13:13:44 +08:00
ChsBuffer
e3e595d469 cut: edit process mode endwith ".exe" check 2020-10-10 00:05:31 +08:00
ChsBuffer
36718e774c feat: mode reference( #include <RelativePathWithoutExtesion.h> ) 2020-10-10 00:02:44 +08:00
ChsBuffer
bf6d3aae95 fix: Process Form high dpi scale 2020-10-09 22:15:36 +08:00
ChsBuffer
477509b12f refactor: VMess.ParseUri
- break: version 1 support
- break: mux config in uri
2020-10-09 20:23:46 +08:00
ChsBuffer
910f6818b0 Revert "mode 2 remove outbound 0.0.0.0/0"
This reverts commit d369858273.
2020-10-09 20:02:59 +08:00
ChsBuffer
ed3f4d1763 refactor: ShareLink.ParseText Non-Nullable
refactor: UpdateServersFromSubscribe
2020-10-09 19:56:47 +08:00
ChsBuffer
be53432a2e refactor: try catch ICSHelper exception #393 2020-10-09 19:21:00 +08:00
ChsBuffer
9d78de0f6c refactor: SubscribeForm Save
- remove: duplicate link check
- fix: check remark duplicate not work
2020-10-08 20:31:50 +08:00
ChsBuffer
75bf753a65 reafactor: ICS Check State 2020-10-08 20:30:42 +08:00
ChsBuffer
3efbad5e5e bump version to 1.6.1 2020-10-07 21:18:37 +08:00
ChsBuffer
020c2d7e67 refactor: merge ServerForm's parital declarations 2020-10-07 21:11:39 +08:00
ChsBuffer
adcc6a75c9 fix: MainForm Text reload got exception when increase profile count #389 2020-10-07 20:54:00 +08:00
ChsBuffer
7e907eef6f fix: ServerForm High DPI Scale #388 2020-10-07 20:37:23 +08:00
ChsBuffer
d213872bde refact: rename TUNTAPController Gateway to Outbound 2020-10-07 19:26:30 +08:00
ChsBuffer
71687c1da6 Revert "Use GetLocalEndPoint to replace GetBestRoute"
This reverts commit 801e8e3b8a.
2020-10-07 19:26:25 +08:00
ChsBuffer
2eb6b23ca7 fix: trojan form 2020-10-07 10:07:55 +08:00
93 changed files with 4327 additions and 7386 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

@@ -5,49 +5,41 @@ jobs:
name: Build
runs-on: windows-latest
steps:
- name: Setup NuGet
uses: nuget/setup-nuget@v1
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.0.1
uses: microsoft/setup-msbuild@v1.0.2
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Restore NuGet Packages Cache
uses: actions/cache@v2
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('Netch/Netch.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore NuGet Package
run: nuget restore Netch.sln
- name: Build Solution
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\win-x64\
7z rn C:\builtfiles\Netch.7z win-x64 Netch
echo "::set-env name=Netch_SHA256::$(.\GetSHA256.ps1 C:\builtfiles\Netch.7z)"
echo "::set-env name=Netch_EXE_SHA256::$(.\GetSHA256.ps1 Netch\bin\x64\Release\win-x64\Netch.exe)"
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\win-x64
path: Netch\bin\x64\Release
- name: Package
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
shell: pwsh
run: |
New-Item -ItemType Directory -Path C:\builtfiles -Force > $null
7z a -mx9 C:\builtfiles\Netch.7z .\Netch\bin\x64\Release\
7z rn C:\builtfiles\Netch.7z Release Netch
echo "Netch_SHA256=$(.\GetSHA256.ps1 C:\builtfiles\Netch.7z)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "Netch_EXE_SHA256=$(.\GetSHA256.ps1 Netch\bin\x64\Release\Netch.exe)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- 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
@@ -63,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

@@ -1,33 +1,12 @@
param([string]$buildtfm = 'all')
Write-Host 'Building'
Write-Host 'DotNet SDK Version'
dotnet --version
msbuild -v:n -m:1 /p:Configuration="Release" `
/p:Platform="x64" `
/p:TargetFramework=net48 `
/p:SolutionDir="..\" `
/restore `
Netch\Netch.csproj
$exe = 'Netch.exe'
$mainDir = (Get-Item -Path ".\").FullName
$net_baseoutput = "$mainDir\Netch\bin\$configuration"
if ($LASTEXITCODE) { exit $LASTEXITCODE }
Write-Host $mainDir
Write-Host $net_baseoutput
function Build-NetFrameworkx64
{
Write-Host 'Building .NET Framework x64'
$outdir = "$net_baseoutput\x64"
msbuild -v:n -m:1 /p:Configuration="Release" `
/p:Platform="x64" `
/p:TargetFramework=net48 `
/p:Runtimeidentifier=win-x64 `
/restore
if ($LASTEXITCODE) { cd $mainDir ; exit $LASTEXITCODE }
Write-Host 'Build done'
}
cd $mainDir
Build-NetFrameworkx64
cd $mainDir
exit 0
Write-Host 'Build done'

View File

@@ -1,5 +1,6 @@
param([string]$file)
$hash = [Security.Cryptography.HashAlgorithm]::Create( "SHA256" )
$stream = ([IO.StreamReader]$file).BaseStream
-join ($hash.ComputeHash($stream) | ForEach { "{0:x2}" -f $_ })
$stream.Close()
$path = (Resolve-Path -Path $file).Path
$stream = ([IO.StreamReader]$path).BaseStream
-join ($hash.ComputeHash($stream) | ForEach-Object { "{0:x2}" -f $_ })
$stream.Close()

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

@@ -15,9 +15,9 @@ 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"))
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)),
Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"),
Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"))
)
return false;
return

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -11,8 +11,6 @@ namespace Netch.Controllers
{
public class HTTPController : IModeController
{
public bool TestNatRequired { get; } = false;
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
public PrivoxyController pPrivoxyController = new PrivoxyController();
@@ -25,25 +23,17 @@ namespace Netch.Controllers
/// <summary>
/// 启动
/// </summary>
/// <param name="s">服务器</param>
/// <param name="mode">模式</param>
/// <returns>是否启动成功</returns>
public bool Start(Server s, Mode mode)
public bool Start(in Mode mode)
{
RecordPrevious();
try
{
if (s.IsSocks5())
if (pPrivoxyController.Start(MainController.Server, mode))
{
var server = (Socks5) s;
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password)) return false;
pPrivoxyController.Start(s, mode);
}
else
{
pPrivoxyController.Start(s, mode);
Global.Job.AddProcess(pPrivoxyController.Instance);
}
if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions);

View File

@@ -7,11 +7,8 @@ namespace Netch.Controllers
/// <summary>
/// 启动
/// </summary>
/// <param name="s">服务器</param>
/// <param name="mode">模式</param>
/// <returns>是否成功</returns>
public abstract bool Start(Server s, Mode mode);
public abstract bool TestNatRequired { get; }
public abstract bool Start(in Mode mode);
}
}

View File

@@ -4,16 +4,29 @@ namespace Netch.Controllers
{
public interface IServerController : IController
{
public int? Socks5LocalPort { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
/// <summary>
/// 启动
/// </summary>
/// <param name="server">服务器</param>
/// <param name="s">服务器</param>
/// <param name="mode">模式</param>
/// <returns>是否启动成功</returns>
public abstract bool Start(Server server, Mode mode);
public abstract bool Start(in Server s, in Mode mode);
}
public static class ServerControllerExtension
{
public static ushort Socks5LocalPort(this IServerController controller)
{
return controller.Socks5LocalPort ?? Global.Settings.Socks5LocalPort;
}
public static string LocalAddress(this IServerController controller)
{
return controller.LocalAddress ?? Global.Settings.LocalAddress;
}
}
}

View File

@@ -1,8 +1,9 @@
using System;
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
using static Netch.Forms.MainForm;
using static Netch.Utils.PortHelper;
@@ -11,12 +12,20 @@ namespace Netch.Controllers
{
public static class MainController
{
public static IServerController ServerController { get; private set; }
public static IServerController ServerController
{
get => _serverController;
private set => _serverController = value;
}
/// TCP or Both Server
public static Server Server;
public static IModeController ModeController { get; private set; }
public static bool NttTested;
private static readonly NTTController NTTController = new NTTController();
private static IServerController _serverController;
/// <summary>
/// 启动
@@ -27,12 +36,14 @@ 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.IsSocks5() && mode.Type == 4)
if (server is Socks5 && mode.Type == 4)
{
return false;
}
// 刷新DNS缓存
NativeMethods.FlushDNSResolverCache();
try
@@ -45,27 +56,33 @@ namespace Netch.Controllers
return false;
}
if (DNS.Lookup(server.Hostname) == null)
if (Global.Settings.ResolveServerHostname && DNS.Lookup(server.Hostname) == null)
{
MessageBoxX.Show("Lookup Server hostname failed");
return false;
}
// 添加Netch到防火墙
_ = Task.Run(Firewall.AddNetchFwRules);
try
{
if (!await StartServer(server, mode))
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 (ModeController?.TestNatRequired ?? false)
if (mode.TestNatRequired())
NatTest();
return true;
@@ -99,70 +116,70 @@ namespace Netch.Controllers
}
}
private static async Task<bool> StartServer(Server server, Mode mode)
private static bool StartServer(Server server, Mode mode, ref IServerController controller)
{
if (server.IsSocks5())
{
return true;
}
controller = ServerHelper.GetUtilByTypeName(server.Type).GetController();
ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
if (ServerController is Guard instanceController)
if (controller is Guard instanceController)
{
Utils.Utils.KillProcessByName(instanceController.MainFile);
}
PortCheckAndShowMessageBox(Global.Settings.Socks5LocalPort, "Socks5");
PortCheckAndShowMessageBox(controller.Socks5LocalPort(), "Socks5");
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
if (await Task.Run(() => ServerController.Start(server, mode)))
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
if (controller.Start(in server, mode))
{
UsingPorts.Add(StatusPortInfoText.Socks5Port = Global.Settings.Socks5LocalPort);
StatusPortInfoText.ShareLan = Global.Settings.LocalAddress == "0.0.0.0";
if (controller is Guard guard)
{
if (guard.Instance != null)
{
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;
}
return false;
}
private static async Task<bool> StartMode(Server server, Mode mode)
private static async Task<bool> StartMode(Mode mode)
{
var port = 0;
switch (mode.Type)
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName, out var portType);
if (ModeController == null)
{
case 0:
ModeController = new NFController();
PortCheckAndShowMessageBox(port = Global.Settings.RedirectorTCPPort, "Redirector TCP");
break;
case 1:
case 2:
ModeController = new TUNTAPController();
break;
case 3:
case 5:
ModeController = new HTTPController();
PortCheckAndShowMessageBox(port = Global.Settings.HTTPLocalPort, "HTTP");
break;
case 4:
return true;
default:
Logging.Error("未知模式类型");
return false;
return true;
}
if (port != null)
{
PortCheckAndShowMessageBox((ushort) port, portName, portType);
UsingPorts.Add((ushort) port);
}
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
if (await Task.Run(() => ModeController.Start(server, mode)))
if (await Task.Run(() => ModeController.Start(mode)))
{
switch (mode.Type)
if (ModeController is Guard guard)
{
case 3:
case 5:
StatusPortInfoText.HttpPort = port;
break;
if (guard.Instance != null)
{
Global.Job.AddProcess(guard.Instance);
}
}
UsingPorts.Add(port);
return true;
}
@@ -175,6 +192,7 @@ namespace Netch.Controllers
public static async Task Stop()
{
UsingPorts.Clear();
StatusPortInfoText.Reset();
_ = Task.Run(() => NTTController.Stop());
@@ -184,6 +202,8 @@ namespace Netch.Controllers
Task.Run(() => ModeController?.Stop()),
};
await Task.WhenAll(tasks);
ModeController = null;
ServerController = null;
}
@@ -195,7 +215,7 @@ namespace Netch.Controllers
/// <param name="portName">端口用途名称</param>
/// <param name="portType"></param>
/// <exception cref="PortInUseException"></exception>
private static void PortCheckAndShowMessageBox(int 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,9 +1,13 @@
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.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
using Netch.Utils;
using nfapinet;
@@ -11,8 +15,6 @@ namespace Netch.Controllers
{
public class NFController : IModeController
{
public bool TestNatRequired { get; } = true;
private static readonly ServiceController NFService = new ServiceController("netfilter2");
private static readonly string BinDriver = string.Empty;
@@ -45,58 +47,196 @@ namespace Netch.Controllers
BinDriver = "bin\\" + fileName;
}
public bool Start(Server s, Mode mode)
public bool Start(in Mode mode)
{
Logging.Info("内置驱动版本: " + Utils.Utils.GetFileVersion(BinDriver));
if (Utils.Utils.GetFileVersion(SystemDriver) != Utils.Utils.GetFileVersion(BinDriver))
if (!CheckDriver())
return false;
#region aio_dial
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
aio_dial((int)NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
if (Global.Settings.ProcessNoProxyForUdp)
{
if (File.Exists(SystemDriver))
{
Logging.Info("系统驱动版本: " + Utils.Utils.GetFileVersion(SystemDriver));
Logging.Info("更新驱动");
UninstallDriver();
}
if (!InstallDriver())
return false;
}
aio_dial((int) NameList.TYPE_CLRNAME, "");
foreach (var rule in mode.Rule)
{
aio_dial((int) NameList.TYPE_ADDNAME, rule);
}
aio_dial((int) NameList.TYPE_ADDNAME, "NTT.exe");
if (s.IsSocks5())
{
var result = DNS.Lookup(s.Hostname);
if (result == null)
{
Logging.Info("无法解析服务器 IP 地址");
return false;
}
aio_dial((int) NameList.TYPE_TCPHOST, $"{result}:{s.Port}");
aio_dial((int) NameList.TYPE_UDPHOST, $"{result}:{s.Port}");
aio_dial((int)NameList.TYPE_FILTERUDP, "false");
SetServer(MainController.ServerController, PortType.TCP);
}
else
{
aio_dial((int) NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
aio_dial((int) NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
aio_dial((int)NameList.TYPE_FILTERUDP, "true");
SetServer(MainController.ServerController, 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;
DNS.OutboundDNS = "1.1.1.1,8.8.8.8";
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);
Logging.Info("内置驱动版本: " + binFileVersion);
Logging.Info("系统驱动版本: " + systemFileVersion);
if (!File.Exists(BinDriver))
{
Logging.Warning("内置驱动不存在");
if (File.Exists(SystemDriver))
{
Logging.Warning("使用系统驱动");
return true;
}
Logging.Error("未安装驱动");
return false;
}
if (!File.Exists(SystemDriver))
{
return InstallDriver();
}
var updateFlag = false;
if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
{
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 IServerController controller, in PortType portType)
{
if (portType == PortType.Both)
{
SetServer(controller, PortType.TCP);
SetServer(controller, PortType.UDP);
return;
}
var offset = portType == PortType.UDP ? UdpNameListOffset : 0;
if (MainController.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 (MainController.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);
}
}
private void SetName(Mode mode)
{
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");
}
public void Stop()
{
Task.Run(() =>
@@ -111,20 +251,44 @@ namespace Netch.Controllers
#region NativeMethods
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aio_init();
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aio_free();
private static extern bool aio_init();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong aio_getUP();
private static extern bool aio_free();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong aio_getDL();
private static extern ulong aio_getUP();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
private static extern ulong aio_getDL();
public enum NameList : int
{
TYPE_FILTERLOOPBACK,
TYPE_FILTERTCP,
TYPE_FILTERUDP,
TYPE_TCPLISN,
TYPE_TCPTYPE,
TYPE_TCPHOST,
TYPE_TCPUSER,
TYPE_TCPPASS,
TYPE_TCPMETH,
TYPE_UDPTYPE,
TYPE_UDPHOST,
TYPE_UDPUSER,
TYPE_UDPPASS,
TYPE_UDPMETH,
TYPE_ADDNAME,
TYPE_BYPNAME,
TYPE_CLRNAME
}
#endregion

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

@@ -1,5 +1,7 @@
using System.IO;
using System.Text;
using Netch.Models;
using Netch.Servers.Socks5;
namespace Netch.Controllers
{
@@ -16,13 +18,21 @@ namespace Netch.Controllers
public bool Start(Server server, Mode mode)
{
var text = File.ReadAllText("bin\\default.conf")
.Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString())
.Replace("_DEST_PORT_", (server.IsSocks5() ? server.Port : Global.Settings.Socks5LocalPort).ToString())
.Replace("0.0.0.0", Global.Settings.LocalAddress);
if (server.IsSocks5())
text = text.Replace("/ 127.0.0.1", $"/ {server.Hostname}");
File.WriteAllText("data\\privoxy.conf", text);
var text = new StringBuilder(File.ReadAllText("bin\\default.conf"));
text.Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString());
text.Replace("0.0.0.0", Global.Settings.LocalAddress); /* BIND_HOST */
if (server is Socks5 socks5 && !socks5.Auth())
{
text.Replace("/ 127.0.0.1", $"/ {server.AutoResolveHostname()}"); /* DEST_HOST */
text.Replace("_DEST_PORT_", socks5.Port.ToString());
}
text.Replace("_DEST_PORT_", Global.Settings.Socks5LocalPort.ToString());
File.WriteAllText("data\\privoxy.conf", text.ToString());
return StartInstanceAuto("..\\data\\privoxy.conf");
}

View File

@@ -1,30 +1,21 @@
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;
namespace Netch.Controllers
{
public class TUNTAPController : Guard, IModeController
{
public bool TestNatRequired { get; } = true;
// ByPassLan IP
private readonly List<string> _bypassLanIPs = new List<string>
{"10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16"};
private Mode _savedMode = new Mode();
private Server _savedServer = new Server();
/// <summary>
/// 服务器 IP 地址
/// </summary>
@@ -44,13 +35,11 @@ namespace Netch.Controllers
public override string Name { get; protected set; } = "tun2socks";
public override string MainFile { get; protected set; } = "tun2socks.exe";
public bool Start(Server s, Mode mode)
public bool Start(in Mode mode)
{
_savedMode = mode;
_savedServer = s;
var server = MainController.Server;
// 查询服务器 IP 地址
_serverAddresses = DNS.Lookup(_savedServer.Hostname);
_serverAddresses = DNS.Lookup(server.Hostname);
// 查找出口适配器
if (!Utils.Utils.SearchOutboundAdapter())
@@ -59,20 +48,28 @@ namespace Netch.Controllers
}
// 查找并安装 TAP 适配器
if (!SearchTapAdapter() && !AddTap())
if (!SearchTapAdapter())
{
Logging.Error("Tap 适配器安装失败");
return false;
if (!AddTap())
{
Logging.Error("Tap 适配器安装失败");
return false;
}
SearchTapAdapter();
}
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
{
@@ -82,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 (s.IsSocks5())
argument.Append($"-proxyServer {_serverAddresses}:{s.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} ");
@@ -115,61 +126,62 @@ namespace Netch.Controllers
Task.WaitAll(tasks);
}
private readonly List<IPNetwork> _directIPs = new List<IPNetwork>();
private readonly List<string> _directIPs = new List<string>();
private readonly List<IPNetwork> _proxyIPs = new List<IPNetwork>();
private readonly List<string> _proxyIPs = new List<string>();
/// <summary>
/// 设置绕行规则
/// </summary>
/// <returns>是否设置成功</returns>
private void SetupRouteTable()
private void SetupRouteTable(Mode mode)
{
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
Logging.Info("设置路由规则");
Logging.Info("绕行 → 全局绕过 IP");
_directIPs.AddRange(Global.Settings.BypassIPs.Select(IPNetwork.Parse));
#region Rule IPs
Logging.Info("绕行 → 服务器 IP");
if (!IPAddress.IsLoopback(_serverAddresses))
_directIPs.Add(IPNetwork.Parse(_serverAddresses.ToString(), 32));
Logging.Info("绕行 → 局域网 IP");
_directIPs.AddRange(_bypassLanIPs.Select(IPNetwork.Parse));
switch (_savedMode.Type)
switch (mode.Type)
{
case 1:
// 代理规则
Logging.Info("代理 → 规则 IP");
_proxyIPs.AddRange(_savedMode.Rule.Select(IPNetwork.Parse));
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP自己记录解析了返回的 IP仅支持默认检测服务器
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
{
try
{
Logging.Info("代理 → STUN 服务器 IP");
_proxyIPs.AddRange(new[]
{
Dns.GetHostAddresses(Global.Settings.STUN_Server)[0],
Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0]
}.Select(ip => IPNetwork.Parse(ip.ToString(), 32)));
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 类型测试域名解析失败,将不会被添加到代理列表");
}
}
if (Global.Settings.TUNTAP.ProxyDNS)
{
Logging.Info("代理 → 自定义 DNS");
if (Global.Settings.TUNTAP.UseCustomDNS)
{
_proxyIPs.AddRange(Global.Settings.TUNTAP.DNS.Select(ip => IPNetwork.Parse(ip, 32)));
RouteAction(Action.Create,
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
else
{
_proxyIPs.AddRange(new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => IPNetwork.Parse(ip, 32)));
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);
}
}
@@ -189,20 +201,25 @@ namespace Netch.Controllers
);
Logging.Info("绕行 → 规则 IP");
_directIPs.AddRange(_savedMode.Rule.Select(IPNetwork.Parse));
Logging.Info("代理 → 全局");
RouteAction(Action.Create, IPNetwork.Parse("0.0.0.0", 0), RouteType.TUNTAP);
Logging.Info("移除 → 出口网卡路由");
RouteAction(Action.Delete, IPNetwork.Parse("0.0.0.0", 0), RouteType.Gateway);
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
break;
}
Logging.Info("设置路由规则");
RouteAction(Action.Create, _directIPs, RouteType.Gateway);
RouteAction(Action.Create, _proxyIPs, RouteType.TUNTAP);
#endregion
Logging.Info("绕行 → 服务器 IP");
if (!IPAddress.IsLoopback(_serverAddresses))
RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound);
Logging.Info("绕行 → 全局绕过 IP");
RouteAction(Action.Create, Global.Settings.BypassIPs, RouteType.Outbound);
if (mode.Type == 2)
{
// 绕过规则
Logging.Info("代理 → 全局");
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP);
}
}
@@ -211,17 +228,7 @@ namespace Netch.Controllers
/// </summary>
private bool ClearRouteTable()
{
switch (_savedMode.Type)
{
case 1:
break;
case 2:
RouteAction(Action.Delete, IPNetwork.Parse("0.0.0.0", 0), RouteType.TUNTAP);
RouteAction(Action.Create, IPNetwork.Parse("0.0.0.0", 0), RouteType.Gateway);
break;
}
RouteAction(Action.Delete, _directIPs, RouteType.Gateway);
RouteAction(Action.Delete, _directIPs, RouteType.Outbound);
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
_directIPs.Clear();
_proxyIPs.Clear();
@@ -231,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
{
@@ -321,7 +306,7 @@ namespace Netch.Controllers
private enum RouteType
{
Gateway,
Outbound,
TUNTAP
}
@@ -331,7 +316,7 @@ namespace Netch.Controllers
Delete
}
private static void RouteAction(Action action, IEnumerable<IPNetwork> ipNetworks, RouteType routeType,
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType,
int metric = 0)
{
foreach (var address in ipNetworks)
@@ -340,13 +325,13 @@ namespace Netch.Controllers
}
}
private static bool RouteAction(Action action, IPNetwork ipNetwork, RouteType routeType, int metric = 0)
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0)
{
string gateway;
int index;
switch (routeType)
{
case RouteType.Gateway:
case RouteType.Outbound:
gateway = Global.Outbound.Gateway.ToString();
index = Global.Outbound.Index;
break;
@@ -358,18 +343,48 @@ namespace Netch.Controllers
throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null);
}
var result = action switch
string network;
ushort cidr;
try
{
Action.Create => NativeMethods.CreateRoute(ipNetwork.Network.ToString(), ipNetwork.Cidr, gateway, index,
metric),
Action.Delete => NativeMethods.DeleteRoute(ipNetwork.Network.ToString(), ipNetwork.Cidr, gateway, index,
metric),
_ => throw new ArgumentOutOfRangeException(nameof(action), action, null)
};
var s = ipNetwork.Split('/');
network = s[0];
cidr = ushort.Parse(s[1]);
}
catch
{
Logging.Warning($"Failed to parse rule {ipNetwork}");
return false;
}
bool result;
switch (action)
{
case Action.Create:
{
result = NativeMethods.CreateRoute(network, cidr, gateway, index, metric);
switch (routeType)
{
case RouteType.Outbound:
_directIPs.Add(ipNetwork);
break;
case RouteType.TUNTAP:
_proxyIPs.Add(ipNetwork);
break;
}
break;
}
case Action.Delete:
result = NativeMethods.DeleteRoute(network, cidr, gateway, index, metric);
break;
default:
throw new ArgumentOutOfRangeException(nameof(action), action, null);
}
if (!result)
{
Logging.Warning($"Failed {action} Route on {routeType} Adapter: {ipNetwork} metric {metric}");
Logging.Warning($"Failed to {action} Route on {routeType} Adapter: {ipNetwork} metric {metric}");
}
return result;

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.0";
public const string AssemblyVersion = @"1.6.8";
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

@@ -85,6 +85,8 @@
this.SettingsButton = new System.Windows.Forms.Button();
this.ProfileGroupBox = new System.Windows.Forms.GroupBox();
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl();
this.MenuStrip.SuspendLayout();
this.ConfigurationGroupBox.SuspendLayout();
this.configLayoutPanel.SuspendLayout();
@@ -99,6 +101,8 @@
this.StatusStrip.SuspendLayout();
this.NotifyMenu.SuspendLayout();
this.ProfileGroupBox.SuspendLayout();
this.flowLayoutPanel1.SuspendLayout();
this.ButtomControlContainerControl.SuspendLayout();
this.SuspendLayout();
//
// MenuStrip
@@ -118,7 +122,7 @@
this.MenuStrip.Location = new System.Drawing.Point(0, 0);
this.MenuStrip.Name = "MenuStrip";
this.MenuStrip.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional;
this.MenuStrip.Size = new System.Drawing.Size(733, 26);
this.MenuStrip.Size = new System.Drawing.Size(740, 26);
this.MenuStrip.TabIndex = 0;
//
// ServerToolStripMenuItem
@@ -202,42 +206,42 @@
// OpenDirectoryToolStripMenuItem
//
this.OpenDirectoryToolStripMenuItem.Name = "OpenDirectoryToolStripMenuItem";
this.OpenDirectoryToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
this.OpenDirectoryToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.OpenDirectoryToolStripMenuItem.Text = "Open Directory";
this.OpenDirectoryToolStripMenuItem.Click += new System.EventHandler(this.OpenDirectoryToolStripMenuItem_Click);
//
// CleanDNSCacheToolStripMenuItem
//
this.CleanDNSCacheToolStripMenuItem.Name = "CleanDNSCacheToolStripMenuItem";
this.CleanDNSCacheToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
this.CleanDNSCacheToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.CleanDNSCacheToolStripMenuItem.Text = "Clean DNS Cache";
this.CleanDNSCacheToolStripMenuItem.Click += new System.EventHandler(this.CleanDNSCacheToolStripMenuItem_Click);
//
// UpdateACLToolStripMenuItem
//
this.UpdateACLToolStripMenuItem.Name = "UpdateACLToolStripMenuItem";
this.UpdateACLToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
this.UpdateACLToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.UpdateACLToolStripMenuItem.Text = "Update ACL";
this.UpdateACLToolStripMenuItem.Click += new System.EventHandler(this.updateACLToolStripMenuItem_Click);
//
// updateACLWithProxyToolStripMenuItem
//
this.updateACLWithProxyToolStripMenuItem.Name = "updateACLWithProxyToolStripMenuItem";
this.updateACLWithProxyToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
this.updateACLWithProxyToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.updateACLWithProxyToolStripMenuItem.Text = "Update ACL with proxy";
this.updateACLWithProxyToolStripMenuItem.Click += new System.EventHandler(this.updateACLWithProxyToolStripMenuItem_Click);
//
// UninstallServiceToolStripMenuItem
//
this.UninstallServiceToolStripMenuItem.Name = "UninstallServiceToolStripMenuItem";
this.UninstallServiceToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
this.UninstallServiceToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.UninstallServiceToolStripMenuItem.Text = "Uninstall NF Service";
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
//
// UninstallTapDriverToolStripMenuItem
//
this.UninstallTapDriverToolStripMenuItem.Name = "UninstallTapDriverToolStripMenuItem";
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.UninstallTapDriverToolStripMenuItem.Text = "Uninstall TUN/TAP driver";
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.reinstallTapDriverToolStripMenuItem_Click);
//
@@ -311,7 +315,7 @@
// ConfigurationGroupBox
//
this.ConfigurationGroupBox.Controls.Add(this.configLayoutPanel);
this.ConfigurationGroupBox.Location = new System.Drawing.Point(12, 28);
this.ConfigurationGroupBox.Location = new System.Drawing.Point(3, 3);
this.ConfigurationGroupBox.Name = "ConfigurationGroupBox";
this.ConfigurationGroupBox.Size = new System.Drawing.Size(709, 115);
this.ConfigurationGroupBox.TabIndex = 1;
@@ -320,6 +324,8 @@
//
// configLayoutPanel
//
this.configLayoutPanel.AutoSize = true;
this.configLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.configLayoutPanel.ColumnCount = 3;
this.configLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.configLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
@@ -336,9 +342,9 @@
this.configLayoutPanel.Location = new System.Drawing.Point(3, 19);
this.configLayoutPanel.Name = "configLayoutPanel";
this.configLayoutPanel.RowCount = 3;
this.configLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.configLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.configLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.configLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.configLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.configLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.configLayoutPanel.Size = new System.Drawing.Size(703, 93);
this.configLayoutPanel.TabIndex = 15;
//
@@ -346,7 +352,7 @@
//
this.ProfileLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ProfileLabel.AutoSize = true;
this.ProfileLabel.Location = new System.Drawing.Point(3, 69);
this.ProfileLabel.Location = new System.Drawing.Point(3, 68);
this.ProfileLabel.Name = "ProfileLabel";
this.ProfileLabel.Size = new System.Drawing.Size(45, 17);
this.ProfileLabel.TabIndex = 10;
@@ -356,7 +362,7 @@
//
this.ModeLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ModeLabel.AutoSize = true;
this.ModeLabel.Location = new System.Drawing.Point(3, 38);
this.ModeLabel.Location = new System.Drawing.Point(3, 36);
this.ModeLabel.Name = "ModeLabel";
this.ModeLabel.Size = new System.Drawing.Size(43, 17);
this.ModeLabel.TabIndex = 3;
@@ -366,7 +372,7 @@
//
this.ServerLabel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.ServerLabel.AutoSize = true;
this.ServerLabel.Location = new System.Drawing.Point(3, 7);
this.ServerLabel.Location = new System.Drawing.Point(3, 6);
this.ServerLabel.Name = "ServerLabel";
this.ServerLabel.Size = new System.Drawing.Size(45, 17);
this.ServerLabel.TabIndex = 0;
@@ -375,7 +381,7 @@
// ProfileNameText
//
this.ProfileNameText.Dock = System.Windows.Forms.DockStyle.Fill;
this.ProfileNameText.Location = new System.Drawing.Point(54, 65);
this.ProfileNameText.Location = new System.Drawing.Point(54, 63);
this.ProfileNameText.Name = "ProfileNameText";
this.ProfileNameText.Size = new System.Drawing.Size(546, 23);
this.ProfileNameText.TabIndex = 11;
@@ -387,7 +393,7 @@
this.ModeComboBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.ModeComboBox.FormattingEnabled = true;
this.ModeComboBox.IntegralHeight = false;
this.ModeComboBox.Location = new System.Drawing.Point(54, 34);
this.ModeComboBox.Location = new System.Drawing.Point(54, 33);
this.ModeComboBox.Name = "ModeComboBox";
this.ModeComboBox.Size = new System.Drawing.Size(546, 24);
this.ModeComboBox.TabIndex = 2;
@@ -435,6 +441,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);
@@ -446,6 +453,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);
@@ -457,6 +465,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);
@@ -468,6 +477,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);
@@ -481,7 +491,7 @@
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
this.tableLayoutPanel3.Controls.Add(this.EditModePictureBox, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.DeleteModePictureBox, 1, 0);
this.tableLayoutPanel3.Location = new System.Drawing.Point(606, 34);
this.tableLayoutPanel3.Location = new System.Drawing.Point(606, 33);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
@@ -495,6 +505,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);
@@ -506,6 +517,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);
@@ -521,9 +533,9 @@
this.blankToolStripStatusLabel,
this.NatTypeStatusLabel,
this.NatTypeStatusLightLabel});
this.StatusStrip.Location = new System.Drawing.Point(0, 250);
this.StatusStrip.Location = new System.Drawing.Point(0, 272);
this.StatusStrip.Name = "StatusStrip";
this.StatusStrip.Size = new System.Drawing.Size(733, 22);
this.StatusStrip.Size = new System.Drawing.Size(740, 22);
this.StatusStrip.SizingGrip = false;
this.StatusStrip.TabIndex = 2;
//
@@ -558,7 +570,7 @@
// blankToolStripStatusLabel
//
this.blankToolStripStatusLabel.Name = "blankToolStripStatusLabel";
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(487, 17);
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(494, 17);
this.blankToolStripStatusLabel.Spring = true;
//
// NatTypeStatusLabel
@@ -584,7 +596,7 @@
// ControlButton
//
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.ControlButton.Location = new System.Drawing.Point(646, 214);
this.ControlButton.Location = new System.Drawing.Point(631, 3);
this.ControlButton.Name = "ControlButton";
this.ControlButton.Size = new System.Drawing.Size(75, 27);
this.ControlButton.TabIndex = 3;
@@ -627,7 +639,7 @@
// SettingsButton
//
this.SettingsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.SettingsButton.Location = new System.Drawing.Point(12, 215);
this.SettingsButton.Location = new System.Drawing.Point(1, 3);
this.SettingsButton.Name = "SettingsButton";
this.SettingsButton.Size = new System.Drawing.Size(72, 27);
this.SettingsButton.TabIndex = 4;
@@ -638,7 +650,7 @@
// ProfileGroupBox
//
this.ProfileGroupBox.Controls.Add(this.ProfileTable);
this.ProfileGroupBox.Location = new System.Drawing.Point(12, 146);
this.ProfileGroupBox.Location = new System.Drawing.Point(3, 124);
this.ProfileGroupBox.Name = "ProfileGroupBox";
this.ProfileGroupBox.Size = new System.Drawing.Size(709, 65);
this.ProfileGroupBox.TabIndex = 13;
@@ -661,17 +673,40 @@
this.ProfileTable.Size = new System.Drawing.Size(703, 43);
this.ProfileTable.TabIndex = 0;
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.AutoSize = true;
this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.flowLayoutPanel1.Controls.Add(this.ConfigurationGroupBox);
this.flowLayoutPanel1.Controls.Add(this.ProfileGroupBox);
this.flowLayoutPanel1.Controls.Add(this.ButtomControlContainerControl);
this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowLayoutPanel1.Location = new System.Drawing.Point(12, 29);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(715, 256);
this.flowLayoutPanel1.TabIndex = 14;
//
// ButtomControlContainerControl
//
this.ButtomControlContainerControl.Controls.Add(this.ControlButton);
this.ButtomControlContainerControl.Controls.Add(this.SettingsButton);
this.ButtomControlContainerControl.Location = new System.Drawing.Point(3, 195);
this.ButtomControlContainerControl.Name = "ButtomControlContainerControl";
this.ButtomControlContainerControl.Size = new System.Drawing.Size(706, 58);
this.ButtomControlContainerControl.TabIndex = 14;
this.ButtomControlContainerControl.TabStop = false;
this.ButtomControlContainerControl.Text = "groupBox1";
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.ClientSize = new System.Drawing.Size(733, 272);
this.Controls.Add(this.ProfileGroupBox);
this.Controls.Add(this.SettingsButton);
this.Controls.Add(this.ControlButton);
this.Controls.Add(this.StatusStrip);
this.Controls.Add(this.ConfigurationGroupBox);
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.ClientSize = new System.Drawing.Size(740, 294);
this.Controls.Add(this.MenuStrip);
this.Controls.Add(this.StatusStrip);
this.Controls.Add(this.flowLayoutPanel1);
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
@@ -685,6 +720,7 @@
this.MenuStrip.ResumeLayout(false);
this.MenuStrip.PerformLayout();
this.ConfigurationGroupBox.ResumeLayout(false);
this.ConfigurationGroupBox.PerformLayout();
this.configLayoutPanel.ResumeLayout(false);
this.configLayoutPanel.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
@@ -700,6 +736,8 @@
this.NotifyMenu.ResumeLayout(false);
this.ProfileGroupBox.ResumeLayout(false);
this.ProfileGroupBox.PerformLayout();
this.flowLayoutPanel1.ResumeLayout(false);
this.ButtomControlContainerControl.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@@ -763,5 +801,7 @@
#endregion
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
@@ -26,19 +27,9 @@ namespace Netch.Forms
var texts = Clipboard.GetText();
if (!string.IsNullOrWhiteSpace(texts))
{
var result = ShareLink.ParseText(texts);
if (result != null)
{
foreach (var server in result)
{
Global.Settings.Server.Add(server);
}
}
else
{
MessageBoxX.Show(i18N.Translate("Import servers error!"), LogLevel.ERROR);
}
var servers = ShareLink.ParseText(texts);
Global.Settings.Server.AddRange(servers);
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", servers.Count));
InitServer();
Configuration.Save();
@@ -108,7 +99,8 @@ namespace Netch.Forms
await UpdateServersFromSubscribe();
}
public async Task UpdateServersFromSubscribe()
private async Task UpdateServersFromSubscribe()
{
void DisableItems(bool v)
{
@@ -132,9 +124,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
{
@@ -142,48 +136,10 @@ namespace Netch.Forms
Type = 5
};
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
}
var serverLock = new object();
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 str = await WebUtil.DownloadStringAsync(request);
lock (serverLock)
{
Global.Settings.Server.RemoveAll(server => server.Group == item.Remark);
var result = ShareLink.ParseText(str);
if (result != null)
{
foreach (var server in result)
{
server.Group = item.Remark;
Global.Settings.Server.Add(server);
}
}
NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, result?.Count ?? 0));
}
}
catch (WebException e)
{
NotifyTip($"{i18N.TranslateFormat("Update servers error from {0}", item.Remark)}\n{e.Message}", info: false);
}
catch (Exception e)
{
Logging.Error(e.ToString());
}
})).ToArray());
await Subscription.UpdateServersAsync(proxyServer);
InitServer();
Configuration.Save();
@@ -195,9 +151,16 @@ namespace Netch.Forms
}
finally
{
if (Global.Settings.UseProxyToUpdateSubscription)
if (useProxyToUpdateSubscription)
{
await MainController.Stop();
try
{
await MainController.Stop();
}
catch
{
// ignored
}
}
DisableItems(true);
@@ -239,7 +202,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)
@@ -260,19 +228,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
@@ -308,7 +270,7 @@ namespace Netch.Forms
State = State.Stopped;
}
DisableItems(true);
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();
@@ -73,7 +98,7 @@ namespace Netch.Forms
{
FileName = Path.Combine(Global.NetchDir, "NetchUpdater.exe"),
Arguments =
$"{Global.Settings.UDPSocketPort} {fileFullPath} {Global.NetchDir}"
$"{Global.Settings.UDPSocketPort} \"{fileFullPath}\" \"{Global.NetchDir}\""
});
}
}

View File

@@ -15,12 +15,8 @@ namespace Netch.Forms
partial class MainForm
{
/// init at <see cref="MainForm_Load"/>
private int _sizeHeight;
private int _profileConfigurationHeight;
private int _profileGroupboxHeight;
private int _configurationGroupBoxHeight;
private int _profileConfigurationHeight;
private void InitProfile()
{
@@ -41,7 +37,6 @@ namespace Netch.Forms
ProfileGroupBox.Visible = false;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight - _profileConfigurationHeight);
Size = new Size(Size.Width, _sizeHeight - (_profileConfigurationHeight + _profileGroupboxHeight));
}
else
{
@@ -75,18 +70,17 @@ namespace Netch.Forms
ProfileTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
}
if (Size.Height == _sizeHeight) return;
configLayoutPanel.RowStyles[2].SizeType = SizeType.AutoSize;
ProfileGroupBox.Visible = true;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight);
Size = new Size(Size.Width, _sizeHeight);
}
}
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.");
@@ -167,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;
@@ -183,34 +185,49 @@ namespace Netch.Forms
public static class StatusPortInfoText
{
public static int Socks5Port = 0;
public static int HttpPort = 0;
public static bool ShareLan = false;
private static ushort? _socks5Port;
private static ushort? _httpPort;
private static bool _shareLan;
public static ushort HttpPort
{
set => _httpPort = value;
}
public static ushort Socks5Port
{
set => _socks5Port = value;
}
public static void UpdateShareLan() => _shareLan = Global.Settings.LocalAddress != "127.0.0.1";
public static string Value
{
get
{
if (Socks5Port == 0 && HttpPort == 0)
return string.Empty;
var strings = new List<string>();
var text = new StringBuilder();
if (ShareLan)
text.Append(i18N.Translate("Allow other Devices to connect") + " ");
if (Socks5Port != 0)
text.Append($"Socks5 {i18N.Translate("Local Port", ": ")}{Socks5Port}");
if (HttpPort != 0)
if (_socks5Port != null)
{
if (Socks5Port != 0)
text.Append(" | ");
text.Append($"HTTP {i18N.Translate("Local Port", ": ")}{HttpPort}");
strings.Add($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
}
return $" ({text})";
if (_httpPort != null)
{
strings.Add($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
}
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;
}
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -63,10 +64,8 @@ namespace Netch.Forms
// 隐藏 NatTypeStatusLabel
NatTypeStatusText();
_sizeHeight = Size.Height;
_configurationGroupBoxHeight = ConfigurationGroupBox.Height;
_profileConfigurationHeight = ConfigurationGroupBox.Controls[0].Height / 3; // 因为 AutoSize, 所以得到的是Controls的总高度
_profileGroupboxHeight = ProfileGroupBox.Height;
// 加载快速配置
InitProfile();
@@ -234,11 +233,12 @@ namespace Netch.Forms
case ListControl _:
break;
case Control c:
c.Text = ControlText(c.Name);
if (_mainFormText.ContainsKey(c.Name))
c.Text = ControlText(c.Name);
break;
case ToolStripItem c:
c.Text = ControlText(c.Name);
if (_mainFormText.ContainsKey(c.Name))
c.Text = ControlText(c.Name);
break;
}
@@ -282,11 +282,20 @@ namespace Netch.Forms
}
Configuration.Save();
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>
@@ -294,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;
}
}
@@ -353,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;
}
}
}
@@ -441,7 +456,7 @@ namespace Netch.Forms
if (WindowState == FormWindowState.Minimized)
{
Visible = true;
ShowInTaskbar = true; // 显示在系统任务栏
ShowInTaskbar = true; // 显示在系统任务栏
WindowState = FormWindowState.Normal; // 还原窗体
}
@@ -458,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

@@ -47,19 +47,21 @@ namespace Netch.Forms.Mode
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.ControlButton = new System.Windows.Forms.Button();
this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.containerControl1 = new System.Windows.Forms.ContainerControl();
this.ConfigurationGroupBox.SuspendLayout();
this.ProcessGroupBox.SuspendLayout();
this.contextMenuStrip.SuspendLayout();
this.containerControl1.SuspendLayout();
this.SuspendLayout();
//
// ConfigurationGroupBox
//
this.ConfigurationGroupBox.Controls.Add(this.containerControl1);
this.ConfigurationGroupBox.Controls.Add(this.UseCustomFilenameBox);
this.ConfigurationGroupBox.Controls.Add(this.FilenameLabel);
this.ConfigurationGroupBox.Controls.Add(this.FilenameTextBox);
this.ConfigurationGroupBox.Controls.Add(this.ScanButton);
this.ConfigurationGroupBox.Controls.Add(this.ProcessGroupBox);
this.ConfigurationGroupBox.Controls.Add(this.RuleListBox);
this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox);
this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel);
this.ConfigurationGroupBox.Location = new System.Drawing.Point(12, 12);
@@ -136,8 +138,9 @@ namespace Netch.Forms.Mode
// RuleListBox
//
this.RuleListBox.FormattingEnabled = true;
this.RuleListBox.Dock = DockStyle.Fill;
this.RuleListBox.ItemHeight = 17;
this.RuleListBox.Location = new System.Drawing.Point(6, 100);
this.RuleListBox.Location = new System.Drawing.Point(0, 0);
this.RuleListBox.Name = "RuleListBox";
this.RuleListBox.Size = new System.Drawing.Size(328, 157);
this.RuleListBox.TabIndex = 2;
@@ -183,6 +186,16 @@ namespace Netch.Forms.Mode
this.DeleteToolStripMenuItem.Text = "Delete";
this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.deleteRule_Click);
//
// containerControl1
//
this.containerControl1.Controls.Add(this.RuleListBox);
this.containerControl1.Location = new System.Drawing.Point(6, 100);
this.containerControl1.Name = "containerControl1";
this.containerControl1.Size = new System.Drawing.Size(328, 157);
this.containerControl1.TabIndex = 10;
this.containerControl1.Padding = new Padding(0);
this.containerControl1.Text = "containerControl1";
//
// Process
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -204,11 +217,13 @@ namespace Netch.Forms.Mode
this.ProcessGroupBox.ResumeLayout(false);
this.ProcessGroupBox.PerformLayout();
this.contextMenuStrip.ResumeLayout(false);
this.containerControl1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ContainerControl containerControl1;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
public System.Windows.Forms.GroupBox ConfigurationGroupBox;

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,27 +140,28 @@ namespace Netch.Forms.Mode
{
await Task.Run(() =>
{
if (!string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
{
var process = ProcessNameTextBox.Text;
if (!process.EndsWith(".exe"))
{
process += ".exe";
}
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

@@ -1,144 +0,0 @@
namespace Netch.Forms
{
partial class ServerForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServerForm));
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
this.AddressLabel = new System.Windows.Forms.Label();
this.PortTextBox = new System.Windows.Forms.TextBox();
this.AddressTextBox = new System.Windows.Forms.TextBox();
this.RemarkTextBox = new System.Windows.Forms.TextBox();
this.RemarkLabel = new System.Windows.Forms.Label();
this.PortLabel = new System.Windows.Forms.Label();
this.ConfigurationGroupBox.SuspendLayout();
this.SuspendLayout();
//
// ConfigurationGroupBox
//
this.ConfigurationGroupBox.AutoSize = true;
this.ConfigurationGroupBox.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.ConfigurationGroupBox.Controls.Add(this.AddressLabel);
this.ConfigurationGroupBox.Controls.Add(this.PortTextBox);
this.ConfigurationGroupBox.Controls.Add(this.AddressTextBox);
this.ConfigurationGroupBox.Controls.Add(this.RemarkTextBox);
this.ConfigurationGroupBox.Controls.Add(this.RemarkLabel);
this.ConfigurationGroupBox.Controls.Add(this.PortLabel);
this.ConfigurationGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.ConfigurationGroupBox.Location = new System.Drawing.Point(5, 5);
this.ConfigurationGroupBox.Name = "ConfigurationGroupBox";
this.ConfigurationGroupBox.Size = new System.Drawing.Size(434, 127);
this.ConfigurationGroupBox.TabIndex = 0;
this.ConfigurationGroupBox.TabStop = false;
this.ConfigurationGroupBox.Text = "Configuration";
//
// AddressLabel
//
this.AddressLabel.AutoSize = true;
this.AddressLabel.Location = new System.Drawing.Point(10, ControlLineHeight*2);
this.AddressLabel.Name = "AddressLabel";
this.AddressLabel.Size = new System.Drawing.Size(56, 17);
this.AddressLabel.TabIndex = 2;
this.AddressLabel.Text = "Address";
//
// PortTextBox
//
this.PortTextBox.Location = new System.Drawing.Point(358, ControlLineHeight*2);
this.PortTextBox.Name = "PortTextBox";
this.PortTextBox.Size = new System.Drawing.Size(56, 23);
this.PortTextBox.TabIndex = 5;
this.PortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// AddressTextBox
//
this.AddressTextBox.Location = new System.Drawing.Point(120, ControlLineHeight*2);
this.AddressTextBox.Name = "AddressTextBox";
this.AddressTextBox.Size = new System.Drawing.Size(232, 23);
this.AddressTextBox.TabIndex = 3;
this.AddressTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// RemarkTextBox
//
this.RemarkTextBox.Location = new System.Drawing.Point(120, ControlLineHeight);
this.RemarkTextBox.Name = "RemarkTextBox";
this.RemarkTextBox.Size = new System.Drawing.Size(294, 23);
this.RemarkTextBox.TabIndex = 1;
this.RemarkTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// RemarkLabel
//
this.RemarkLabel.AutoSize = true;
this.RemarkLabel.Location = new System.Drawing.Point(10, ControlLineHeight);
this.RemarkLabel.Name = "RemarkLabel";
this.RemarkLabel.Size = new System.Drawing.Size(53, 17);
this.RemarkLabel.TabIndex = 0;
this.RemarkLabel.Text = "Remark";
//
// PortLabel
//
this.PortLabel.AutoSize = true;
this.PortLabel.Location = new System.Drawing.Point(351, ControlLineHeight*2);
this.PortLabel.Name = "PortLabel";
this.PortLabel.Size = new System.Drawing.Size(11, 17);
this.PortLabel.TabIndex = 4;
this.PortLabel.Text = ":";
//
// ServerForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.ClientSize = new System.Drawing.Size(444, 137);
this.Controls.Add(this.ConfigurationGroupBox);
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte) (134)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon) (resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.MaximizeBox = false;
this.Name = "ServerForm";
this.Padding = new System.Windows.Forms.Padding(11, 5, 11, 4);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Load += new System.EventHandler(this.ServerForm_Load);
this.ConfigurationGroupBox.ResumeLayout(false);
this.ConfigurationGroupBox.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.GroupBox ConfigurationGroupBox;
private System.Windows.Forms.Label RemarkLabel;
protected System.Windows.Forms.TextBox RemarkTextBox;
private System.Windows.Forms.Label PortLabel;
protected System.Windows.Forms.TextBox AddressTextBox;
private System.Windows.Forms.TextBox PortTextBox;
private System.Windows.Forms.Label AddressLabel;
}
}

View File

@@ -1,14 +1,16 @@
using System;
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Forms
{
public abstract partial class ServerForm : Form
public abstract class ServerForm : Form
{
protected abstract string TypeName { get; }
protected Server Server { get; set; }
@@ -32,6 +34,35 @@ namespace Netch.Forms
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string) s));
}
public new void ShowDialog()
{
AfterFactor();
base.ShowDialog();
}
public new void Show()
{
AfterFactor();
base.Show();
}
private void AfterFactor()
{
Text = TypeName ?? string.Empty;
RemarkTextBox.Text = Server.Remark;
AddressTextBox.Text = Server.Hostname;
PortTextBox.Text = Server.Port.ToString();
AddSaveButton();
i18N.TranslateForm(this);
ConfigurationGroupBox.ResumeLayout(false);
ConfigurationGroupBox.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
protected void CreateTextBox(string name, string remark, Func<string, bool> check, Action<string> save, string value, int width = InputBoxWidth)
{
_controlLines++;
@@ -120,18 +151,6 @@ namespace Netch.Forms
private readonly Dictionary<Control, Action<object>> _saveActions = new Dictionary<Control, Action<object>>();
private void ServerForm_Load(object sender, EventArgs e)
{
Text = TypeName ?? string.Empty;
RemarkTextBox.Text = Server.Remark;
AddressTextBox.Text = Server.Hostname;
PortTextBox.Text = Server.Port.ToString();
AddSaveButton();
i18N.TranslateForm(this);
}
private void AddSaveButton()
{
_controlLines++;
@@ -149,30 +168,158 @@ 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();
}
private IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing)
{
components?.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
ConfigurationGroupBox = new GroupBox();
AddressLabel = new Label();
PortTextBox = new TextBox();
AddressTextBox = new TextBox();
RemarkTextBox = new TextBox();
RemarkLabel = new Label();
PortLabel = new Label();
ConfigurationGroupBox.SuspendLayout();
SuspendLayout();
//
// ConfigurationGroupBox
//
ConfigurationGroupBox.AutoSize = true;
ConfigurationGroupBox.AutoSizeMode = AutoSizeMode.GrowAndShrink;
ConfigurationGroupBox.Controls.Add(AddressLabel);
ConfigurationGroupBox.Controls.Add(PortTextBox);
ConfigurationGroupBox.Controls.Add(AddressTextBox);
ConfigurationGroupBox.Controls.Add(RemarkTextBox);
ConfigurationGroupBox.Controls.Add(RemarkLabel);
ConfigurationGroupBox.Controls.Add(PortLabel);
ConfigurationGroupBox.Dock = DockStyle.Fill;
ConfigurationGroupBox.Location = new Point(5, 5);
ConfigurationGroupBox.Name = "ConfigurationGroupBox";
ConfigurationGroupBox.Size = new Size(434, 127);
ConfigurationGroupBox.TabIndex = 0;
ConfigurationGroupBox.TabStop = false;
ConfigurationGroupBox.Text = "Configuration";
//
// AddressLabel
//
AddressLabel.AutoSize = true;
AddressLabel.Location = new Point(10, ControlLineHeight * 2);
AddressLabel.Name = "AddressLabel";
AddressLabel.Size = new Size(56, 17);
AddressLabel.TabIndex = 2;
AddressLabel.Text = "Address";
//
// PortTextBox
//
PortTextBox.Location = new Point(358, ControlLineHeight * 2);
PortTextBox.Name = "PortTextBox";
PortTextBox.Size = new Size(56, 23);
PortTextBox.TabIndex = 5;
PortTextBox.TextAlign = HorizontalAlignment.Center;
//
// AddressTextBox
//
AddressTextBox.Location = new Point(120, ControlLineHeight * 2);
AddressTextBox.Name = "AddressTextBox";
AddressTextBox.Size = new Size(232, 23);
AddressTextBox.TabIndex = 3;
AddressTextBox.TextAlign = HorizontalAlignment.Center;
//
// RemarkTextBox
//
RemarkTextBox.Location = new Point(120, ControlLineHeight);
RemarkTextBox.Name = "RemarkTextBox";
RemarkTextBox.Size = new Size(294, 23);
RemarkTextBox.TabIndex = 1;
RemarkTextBox.TextAlign = HorizontalAlignment.Center;
//
// RemarkLabel
//
RemarkLabel.AutoSize = true;
RemarkLabel.Location = new Point(10, ControlLineHeight);
RemarkLabel.Name = "RemarkLabel";
RemarkLabel.Size = new Size(53, 17);
RemarkLabel.TabIndex = 0;
RemarkLabel.Text = "Remark";
//
// PortLabel
//
PortLabel.AutoSize = true;
PortLabel.Location = new Point(351, ControlLineHeight * 2);
PortLabel.Name = "PortLabel";
PortLabel.Size = new Size(11, 17);
PortLabel.TabIndex = 4;
PortLabel.Text = ":";
//
// ServerForm
//
AutoScaleDimensions = new SizeF(96F, 96F);
AutoScaleMode = AutoScaleMode.Dpi;
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
ClientSize = new Size(444, 137);
Controls.Add(ConfigurationGroupBox);
Font = new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, (byte) 134);
FormBorderStyle = FormBorderStyle.FixedSingle;
Icon = Icon.FromHandle(Resources.Netch.GetHicon());
Margin = new Padding(3, 4, 3, 4);
MaximizeBox = false;
Name = "ServerForm";
Padding = new Padding(11, 5, 11, 4);
StartPosition = FormStartPosition.CenterScreen;
}
private GroupBox ConfigurationGroupBox;
private Label RemarkLabel;
protected TextBox RemarkTextBox;
private Label PortLabel;
protected TextBox AddressTextBox;
private TextBox PortTextBox;
private Label AddressLabel;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,13 @@
using System;
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 Netch.Controllers;
using Netch.Utils;
using TaskScheduler;
namespace Netch.Forms
{
@@ -15,55 +16,241 @@ namespace Netch.Forms
public SettingForm()
{
InitializeComponent();
i18N.TranslateForm(this);
InitValue();
}
private void SettingForm_Load(object sender, EventArgs e)
{
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns)));
}
private void InitValue()
{
// Local Port
Socks5PortTextBox.Text = Global.Settings.Socks5LocalPort.ToString();
HTTPPortTextBox.Text = Global.Settings.HTTPLocalPort.ToString();
RedirectorTextBox.Text = Global.Settings.RedirectorTCPPort.ToString();
AllowDevicesCheckBox.Checked = Global.Settings.LocalAddress switch
{
"127.0.0.1" => false,
"0.0.0.0" => true,
_ => false
};
#region General
// TUN/TAP
TUNTAPAddressTextBox.Text = Global.Settings.TUNTAP.Address;
TUNTAPNetmaskTextBox.Text = Global.Settings.TUNTAP.Netmask;
TUNTAPGatewayTextBox.Text = Global.Settings.TUNTAP.Gateway;
UseCustomDNSCheckBox.Checked = Global.Settings.TUNTAP.UseCustomDNS;
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
ProxyDNSCheckBox.Checked = Global.Settings.TUNTAP.ProxyDNS;
UseFakeDNSCheckBox.Checked = Global.Settings.TUNTAP.UseFakeDNS;
BindTextBox<ushort>(Socks5PortTextBox,
p => p.ToString() != HTTPPortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
p => Global.Settings.Socks5LocalPort = p,
Global.Settings.Socks5LocalPort);
BindTextBox<ushort>(HTTPPortTextBox,
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
p => Global.Settings.HTTPLocalPort = p,
Global.Settings.HTTPLocalPort);
BindTextBox<ushort>(RedirectorTextBox,
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != HTTPPortTextBox.Text,
p => Global.Settings.RedirectorTCPPort = p,
Global.Settings.RedirectorTCPPort);
BindCheckBox(AllowDevicesCheckBox,
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
Global.Settings.LocalAddress switch
{
"127.0.0.1" => false,
"0.0.0.0" => true,
_ => false
});
if (TUNTAPController.SearchTapAdapter())
{
ICSCheckBox.Enabled = true;
ICSCheckBox.Checked = ICSHelper.Enabled;
}
BindCheckBox(BootShadowsocksFromDLLCheckBox,
c => Global.Settings.BootShadowsocksFromDLL = c,
Global.Settings.BootShadowsocksFromDLL);
BindCheckBox(ResolveServerHostnameCheckBox,
c => Global.Settings.ResolveServerHostname = c,
Global.Settings.ResolveServerHostname);
// Behavior
ExitWhenClosedCheckBox.Checked = Global.Settings.ExitWhenClosed;
StopWhenExitedCheckBox.Checked = Global.Settings.StopWhenExited;
StartWhenOpenedCheckBox.Checked = Global.Settings.StartWhenOpened;
MinimizeWhenStartedCheckBox.Checked = Global.Settings.MinimizeWhenStarted;
RunAtStartupCheckBox.Checked = Global.Settings.RunAtStartup;
CheckUpdateWhenOpenedCheckBox.Checked = Global.Settings.CheckUpdateWhenOpened;
BootShadowsocksFromDLLCheckBox.Checked = Global.Settings.BootShadowsocksFromDLL;
CheckBetaUpdateCheckBox.Checked = Global.Settings.CheckBetaUpdate;
ModifySystemDNSCheckBox.Checked = Global.Settings.ModifySystemDNS;
UpdateSubscribeatWhenOpenedCheckBox.Checked = Global.Settings.UpdateSubscribeatWhenOpened;
BindTextBox<int>(ProfileCountTextBox,
i => i > -1,
i => Global.Settings.ProfileCount = i,
Global.Settings.ProfileCount);
BindCheckBox(TcpingAtStartedCheckBox,
b => Global.Settings.StartedTcping = b,
Global.Settings.StartedTcping);
BindTextBox<int>(DetectionIntervalTextBox,
i => i >= 0,
i => Global.Settings.StartedTcping_Interval = i,
Global.Settings.StartedTcping_Interval);
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
TcpingAtStartedCheckBox.Checked = Global.Settings.StartedTcping;
DetectionIntervalTextBox.Text = Global.Settings.StartedTcping_Interval.ToString();
InitSTUN();
BindTextBox<string>(AclAddrTextBox,
s => true,
s => Global.Settings.ACL = s,
Global.Settings.ACL);
AclAddrTextBox.Text = Global.Settings.ACL;
LanguageComboBox.Items.AddRange(i18N.GetTranslateList().ToArray());
LanguageComboBox.SelectedItem = Global.Settings.Language;
#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);
#endregion
#region TUN/TAP
BindTextBox(TUNTAPAddressTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.TUNTAP.Address = s,
Global.Settings.TUNTAP.Address);
BindTextBox(TUNTAPNetmaskTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.TUNTAP.Netmask = s,
Global.Settings.TUNTAP.Netmask);
BindTextBox(TUNTAPGatewayTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.TUNTAP.Gateway = s,
Global.Settings.TUNTAP.Gateway);
BindCheckBox(UseCustomDNSCheckBox,
b => { Global.Settings.TUNTAP.UseCustomDNS = b; },
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);
BindCheckBox(UseFakeDNSCheckBox,
b => Global.Settings.TUNTAP.UseFakeDNS = b,
Global.Settings.TUNTAP.UseFakeDNS);
try
{
var icsHelperEnabled = ICSHelper.Enabled;
if (icsHelperEnabled != null)
{
ICSCheckBox.Enabled = true;
ICSCheckBox.Checked = (bool) icsHelperEnabled;
}
}
catch
{
// ignored
}
#endregion
#region V2Ray
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,
i => Global.Settings.V2RayConfig.KcpConfig.mtu = i,
Global.Settings.V2RayConfig.KcpConfig.mtu);
BindTextBox<int>(ttiTextBox,
i => true,
i => Global.Settings.V2RayConfig.KcpConfig.tti = i,
Global.Settings.V2RayConfig.KcpConfig.tti);
BindTextBox<int>(uplinkCapacityTextBox,
i => true,
i => Global.Settings.V2RayConfig.KcpConfig.uplinkCapacity = i,
Global.Settings.V2RayConfig.KcpConfig.uplinkCapacity);
BindTextBox<int>(downlinkCapacityTextBox,
i => true,
i => Global.Settings.V2RayConfig.KcpConfig.downlinkCapacity = i,
Global.Settings.V2RayConfig.KcpConfig.downlinkCapacity);
BindTextBox<int>(readBufferSizeTextBox,
i => true,
i => Global.Settings.V2RayConfig.KcpConfig.readBufferSize = i,
Global.Settings.V2RayConfig.KcpConfig.readBufferSize);
BindTextBox<int>(writeBufferSizeTextBox,
i => true,
i => Global.Settings.V2RayConfig.KcpConfig.writeBufferSize = i,
Global.Settings.V2RayConfig.KcpConfig.writeBufferSize);
BindCheckBox(congestionCheckBox,
b => Global.Settings.V2RayConfig.KcpConfig.congestion = b,
Global.Settings.V2RayConfig.KcpConfig.congestion);
#endregion
#region Others
BindCheckBox(ExitWhenClosedCheckBox,
b => Global.Settings.ExitWhenClosed = b,
Global.Settings.ExitWhenClosed);
BindCheckBox(StopWhenExitedCheckBox,
b => Global.Settings.StopWhenExited = b,
Global.Settings.StopWhenExited);
BindCheckBox(StartWhenOpenedCheckBox,
b => Global.Settings.StartWhenOpened = b,
Global.Settings.StartWhenOpened);
BindCheckBox(MinimizeWhenStartedCheckBox,
b => Global.Settings.MinimizeWhenStarted = b,
Global.Settings.MinimizeWhenStarted);
BindCheckBox(RunAtStartupCheckBox,
b => Global.Settings.RunAtStartup = b,
Global.Settings.RunAtStartup);
BindCheckBox(CheckUpdateWhenOpenedCheckBox,
b => Global.Settings.CheckUpdateWhenOpened = b,
Global.Settings.CheckUpdateWhenOpened);
BindCheckBox(CheckBetaUpdateCheckBox,
b => Global.Settings.CheckBetaUpdate = b,
Global.Settings.CheckBetaUpdate);
BindCheckBox(UpdateSubscribeatWhenOpenedCheckBox,
b => Global.Settings.UpdateSubscribeatWhenOpened = b,
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)
@@ -73,19 +260,15 @@ 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";
}
}
private void InitText()
{
i18N.TranslateForm(this);
}
private void InitSTUN()
{
@@ -94,7 +277,7 @@ namespace Netch.Forms
var stuns = File.ReadLines("bin\\stun.txt");
STUN_ServerComboBox.Items.AddRange(stuns.ToArray());
}
catch (Exception)
catch
{
// ignored
}
@@ -102,13 +285,6 @@ namespace Netch.Forms
STUN_ServerComboBox.Text = $"{Global.Settings.STUN_Server}:{Global.Settings.STUN_Server_Port}";
}
private void SettingForm_Load(object sender, EventArgs e)
{
UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns;
InitText();
InitValue();
}
private void GlobalBypassIPsButton_Click(object sender, EventArgs e)
{
Hide();
@@ -118,161 +294,48 @@ namespace Netch.Forms
private void ControlButton_Click(object sender, EventArgs e)
{
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
#region Check
#region Port
int socks5LocalPort;
int httpLocalPort;
int redirectorTCPPort;
try
var flag = true;
foreach (var pair in _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)))
{
socks5LocalPort = int.Parse(Socks5PortTextBox.Text);
httpLocalPort = int.Parse(HTTPPortTextBox.Text);
redirectorTCPPort = int.Parse(RedirectorTextBox.Text);
static void CheckPort(string portName, int port, int originPort, PortType portType = PortType.Both)
{
if (port <= 0 || port > 65536)
throw new FormatException();
if (port == originPort)
return;
if (PortHelper.PortInUse(port, portType))
{
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
throw new PortInUseException();
}
}
CheckPort("Socks5", socks5LocalPort, Global.Settings.Socks5LocalPort);
CheckPort("HTTP", httpLocalPort, Global.Settings.HTTPLocalPort);
CheckPort("RedirectorTCP", redirectorTCPPort, Global.Settings.RedirectorTCPPort);
Utils.Utils.ChangeControlForeColor(pair.Key, Color.Red);
flag = false;
}
catch (Exception exception)
{
switch (exception)
{
case FormatException _:
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
break;
case PortInUseException _:
break;
}
if (!flag)
{
return;
}
#endregion
#region TUNTAP
#region CheckSTUN
var dns = new string[0];
try
var stunFlag = true;
var stunServer = string.Empty;
ushort stunServerPort = 3478;
var stun = STUN_ServerComboBox.Text.Split(':');
if (stun.Any())
{
IPAddress.Parse(TUNTAPAddressTextBox.Text);
IPAddress.Parse(TUNTAPNetmaskTextBox.Text);
IPAddress.Parse(TUNTAPGatewayTextBox.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;
}
}
}
catch (Exception exception)
{
if (exception is FormatException)
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
TUNTAPAddressTextBox.Text = Global.Settings.TUNTAP.Address;
TUNTAPNetmaskTextBox.Text = Global.Settings.TUNTAP.Netmask;
TUNTAPGatewayTextBox.Text = Global.Settings.TUNTAP.Gateway;
UseCustomDNSCheckBox.Checked = Global.Settings.TUNTAP.UseCustomDNS;
if (UseCustomDNSCheckBox.Checked)
{
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
}
return;
}
#endregion
#region Behavior
// Profile
int profileCount;
try
{
profileCount = int.Parse(ProfileCountTextBox.Text);
if (profileCount <= -1)
{
throw new FormatException();
}
}
catch (FormatException)
{
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
MessageBoxX.Show(i18N.Translate("ProfileCount value illegal. Try again."));
return;
}
// Started TCPing Interval
int detectionInterval;
try
{
detectionInterval = int.Parse(DetectionIntervalTextBox.Text);
if (detectionInterval <= 0)
{
throw new FormatException();
}
}
catch (FormatException)
{
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
MessageBoxX.Show(i18N.Translate("Detection interval value illegal. Try again."));
return;
}
// STUN
string stunServer;
int stunServerPort;
try
{
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))
{
stunFlag = false;
}
}
catch (FormatException)
else
{
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
MessageBoxX.Show(i18N.Translate("STUN_ServerPort value illegal. Try again."));
stunFlag = false;
}
if (!stunFlag)
{
Utils.Utils.ChangeControlForeColor(STUN_ServerComboBox, Color.Red);
return;
}
@@ -282,103 +345,18 @@ namespace Netch.Forms
#region Save
#region Port
Global.Settings.Socks5LocalPort = socks5LocalPort;
Global.Settings.HTTPLocalPort = httpLocalPort;
Global.Settings.RedirectorTCPPort = redirectorTCPPort;
Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1";
#endregion
#region TUNTAP
Global.Settings.TUNTAP.Address = TUNTAPAddressTextBox.Text;
Global.Settings.TUNTAP.Netmask = TUNTAPNetmaskTextBox.Text;
Global.Settings.TUNTAP.Gateway = TUNTAPGatewayTextBox.Text;
Global.Settings.TUNTAP.UseCustomDNS = UseCustomDNSCheckBox.Checked;
if (Global.Settings.TUNTAP.UseCustomDNS)
foreach (var pair in _saveActions)
{
Global.Settings.TUNTAP.DNS.Clear();
Global.Settings.TUNTAP.DNS.AddRange(dns);
pair.Value.Invoke(pair.Key);
}
Global.Settings.TUNTAP.ProxyDNS = ProxyDNSCheckBox.Checked;
Global.Settings.TUNTAP.UseFakeDNS = UseFakeDNSCheckBox.Checked;
#endregion
#region Behavior
Global.Settings.ExitWhenClosed = ExitWhenClosedCheckBox.Checked;
Global.Settings.StopWhenExited = StopWhenExitedCheckBox.Checked;
Global.Settings.StartWhenOpened = StartWhenOpenedCheckBox.Checked;
Global.Settings.MinimizeWhenStarted = MinimizeWhenStartedCheckBox.Checked;
Global.Settings.RunAtStartup = RunAtStartupCheckBox.Checked;
Global.Settings.CheckUpdateWhenOpened = CheckUpdateWhenOpenedCheckBox.Checked;
Global.Settings.BootShadowsocksFromDLL = BootShadowsocksFromDLLCheckBox.Checked;
Global.Settings.CheckBetaUpdate = CheckBetaUpdateCheckBox.Checked;
Global.Settings.ModifySystemDNS = ModifySystemDNSCheckBox.Checked;
Global.Settings.UpdateSubscribeatWhenOpened = UpdateSubscribeatWhenOpenedCheckBox.Checked;
Global.Settings.ProfileCount = profileCount;
Global.Settings.StartedTcping = TcpingAtStartedCheckBox.Checked;
Global.Settings.StartedTcping_Interval = detectionInterval;
Global.Settings.STUN_Server = stunServer;
Global.Settings.STUN_Server_Port = stunServerPort;
Global.Settings.ACL = AclAddrTextBox.Text;
Global.Settings.Language = LanguageComboBox.SelectedItem.ToString();
Global.Settings.Language = LanguageComboBox.Text;
#endregion
#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"));
@@ -387,20 +365,69 @@ namespace Netch.Forms
private async void ICSCheckBox_CheckedChanged(object sender, EventArgs e)
{
ICSCheckBox.Enabled = false;
await Task.Run(() =>
try
{
if (ICSCheckBox.Checked)
ICSCheckBox.Enabled = false;
await Task.Run(() =>
{
if (!ICSHelper.Enabled)
ICSCheckBox.Checked = ICSHelper.Enable();
if (ICSCheckBox.Checked)
{
if (!(ICSHelper.Enabled ?? true))
ICSCheckBox.Checked = ICSHelper.Enable();
}
else
{
ICSHelper.Disable();
}
});
}
catch (Exception exception)
{
ICSCheckBox.Checked = false;
Logging.Error(exception.ToString());
}
finally
{
ICSCheckBox.Enabled = true;
}
}
private void BindTextBox(TextBox control, Func<string, bool> check, Action<string> save, object value)
{
BindTextBox<string>(control, check, save, value);
}
private void BindTextBox<T>(TextBox control, Func<T, bool> check, Action<T> save, object value)
{
control.Text = value.ToString();
_checkActions.Add(control, s =>
{
try
{
return check.Invoke((T) Convert.ChangeType(s, typeof(T)));
}
else
catch
{
ICSHelper.Disable();
return false;
}
});
ICSCheckBox.Enabled = true;
_saveActions.Add(control, c => save.Invoke((T) Convert.ChangeType(((TextBox) c).Text, typeof(T))));
}
private void BindCheckBox(CheckBox control, Action<bool> save, bool value)
{
control.Checked = value;
_checkActions.Add(control, s => true);
_saveActions.Add(control, c => save.Invoke(((CheckBox) 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;
}
}
}

View File

@@ -81,11 +81,11 @@
//
// ClearButton
//
this.ClearButton.Location = new System.Drawing.Point(477, 103);
this.ClearButton.Location = new System.Drawing.Point(448, 103);
this.ClearButton.Name = "ClearButton";
this.ClearButton.Size = new System.Drawing.Size(58, 26);
this.ClearButton.Size = new System.Drawing.Size(87, 26);
this.ClearButton.TabIndex = 7;
this.ClearButton.Text = "Clear";
this.ClearButton.Text = "Unselect";
this.ClearButton.UseVisualStyleBackColor = true;
this.ClearButton.Click += new System.EventHandler(this.ClearButton_Click);
//
@@ -114,7 +114,6 @@
this.LinkTextBox.Name = "LinkTextBox";
this.LinkTextBox.Size = new System.Drawing.Size(545, 23);
this.LinkTextBox.TabIndex = 4;
this.LinkTextBox.TextChanged += new System.EventHandler(this.ListTextBox_TextChanged);
//
// LinkLabel
//

View File

@@ -109,39 +109,23 @@ namespace Netch.Forms
return;
}
// 备注重复的订阅项
var duplicateRemarkItems = Global.Settings.SubscribeLink.Where(link => link.Remark.Equals(RemarkLabel.Text));
// 链接重复的订阅项
SubscribeLink duplicateLinkItem = null;
try
if (_editingIndex == -1)
{
duplicateLinkItem = Global.Settings.SubscribeLink.First(link => link.Link.Equals(LinkTextBox.Text));
}
catch
{
// ignored
}
if (duplicateRemarkItems.Any())
{
MessageBoxX.Show("Remark Name Duplicate!");
return;
}
if (duplicateLinkItem != null)
{
if (duplicateLinkItem.Remark != RemarkTextBox.Text)
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
{
RenameServersGroup(duplicateLinkItem.Remark, RemarkTextBox.Text);
MessageBoxX.Show("Remark Name Duplicate!");
return;
}
duplicateLinkItem.Remark = RemarkTextBox.Text;
duplicateLinkItem.UserAgent = UserAgentTextBox.Text;
Global.Settings.SubscribeLink.Add(new SubscribeLink
{
Remark = RemarkTextBox.Text,
Link = LinkTextBox.Text,
UserAgent = UserAgentTextBox.Text
});
}
else if (_editingIndex != -1)
else
{
// 只修改备注/未修改被上面处理
var target = Global.Settings.SubscribeLink[_editingIndex];
if (MessageBox.Show(i18N.Translate("Delete the corresponding group of items in the server list?"), i18N.Translate("Confirm"), MessageBoxButtons.YesNo) == DialogResult.Yes)
{
@@ -156,15 +140,6 @@ namespace Netch.Forms
target.Remark = RemarkTextBox.Text;
target.UserAgent = UserAgentTextBox.Text;
}
else
{
Global.Settings.SubscribeLink.Add(new SubscribeLink
{
Remark = RemarkTextBox.Text,
Link = LinkTextBox.Text,
UserAgent = UserAgentTextBox.Text
});
}
Configuration.Save();
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
@@ -260,17 +235,5 @@ namespace Netch.Forms
{
ResetEditingGroup();
}
private void ListTextBox_TextChanged(object sender, EventArgs e)
{
for (var i = 0; i < SubscribeLinkListView.Items.Count; i++)
{
if (((TextBox) sender).Text == SubscribeLinkListView.Items[i].SubItems[1].Text)
{
_editingIndex = i;
AddSubscriptionBox.Text = SubscribeLinkListView.Items[i].SubItems[0].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

@@ -28,13 +28,13 @@ namespace Netch.Models
/// </summary>
string[] UriScheme { get; }
Server ParseJObject(JObject j);
Server ParseJObject(in JObject j);
public void Edit(Server s);
public void Create();
string GetShareLink(Server server);
string GetShareLink(Server s);
public abstract IServerController GetController();

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Netch.Utils;
namespace Netch.Models
@@ -42,6 +43,65 @@ namespace Netch.Models
/// </summary>
public readonly List<string> Rule = new List<string>();
public List<string> FullRule
{
get
{
var result = new List<string>();
foreach (var s in Rule)
{
if (string.IsNullOrWhiteSpace(s))
continue;
if (s.StartsWith("//"))
continue;
if (s.StartsWith("#include"))
{
var relativePath = new StringBuilder(s.Substring(8).Trim());
relativePath.Replace("<", "");
relativePath.Replace(">", "");
relativePath.Replace(".h", ".txt");
var mode = Global.Modes.FirstOrDefault(m => m.RelativePath.Equals(relativePath.ToString()));
if (mode == null)
{
Logging.Warning($"{relativePath} file included in {Remark} not found");
}
else if (mode == this)
{
Logging.Warning("Can't self-reference");
}
else
{
if (mode.Type != Type)
{
Logging.Warning($"{mode.Remark}'s mode is not as same as {Remark}'s mode");
}
else
{
if (mode.Rule.Any(rule => rule.StartsWith("#include")))
{
Logging.Warning("Cannot reference mode that reference other mode");
}
else
{
result.AddRange(mode.FullRule);
}
}
}
}
else
{
result.Add(s);
}
}
return result;
}
}
/// <summary>
/// 获取备注
/// </summary>
@@ -57,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>
/// 备注
@@ -34,29 +34,30 @@ namespace Netch.Models
/// <summary>
/// 端口
/// </summary>
public int Port;
public ushort Port;
/// <summary>
/// 延迟
/// </summary>
public int Delay = -1;
public bool IsSocks5() => Type == "Socks5";
/// <summary>
/// 获取备注
/// </summary>
/// <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>
@@ -101,4 +102,12 @@ namespace Netch.Models
}
}
}
public static class ServerExtension
{
public static string AutoResolveHostname(this Server server)
{
return Global.Settings.ResolveServerHostname ? DNS.Lookup(server.Hostname).ToString() : server.Hostname;
}
}
}

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Netch.Models
{
@@ -43,6 +45,41 @@ namespace Netch.Models
public bool UseFakeDNS = false;
}
public class KcpConfig
{
public int mtu = 1350;
public int tti = 50;
public int uplinkCapacity = 12;
public int downlinkCapacity = 100;
public bool congestion = false;
public int readBufferSize = 2;
public int writeBufferSize = 2;
}
public class V2rayConfig
{
public bool AllowInsecure = true;
public KcpConfig KcpConfig = new KcpConfig();
public bool UseMux = true;
}
public class AioDNSConfig
{
public string RulePath = "bin\\china_site_list";
public string ChinaDNS = "223.5.5.5";
public string OtherDNS = "1.1.1.1";
}
/// <summary>
/// 用于读取和写入的配置的类
/// </summary>
@@ -103,6 +140,16 @@ namespace Netch.Models
/// </summary>
public bool ModifySystemDNS = false;
/// <summary>
/// 要修改为的系统 DNS
/// </summary>
public string ModifiedDNS = "1.1.1.1,8.8.8.8";
/// <summary>
/// 解析服务器主机名
/// </summary>
public bool ResolveServerHostname = false;
/// <summary>
/// 网页请求超时 毫秒
/// </summary>
@@ -111,22 +158,22 @@ namespace Netch.Models
/// <summary>
/// HTTP 本地端口
/// </summary>
public int HTTPLocalPort = 2802;
public ushort HTTPLocalPort = 2802;
/// <summary>
/// Socks5 本地端口
/// </summary>
public int Socks5LocalPort = 2801;
public ushort Socks5LocalPort = 2801;
/// <summary>
/// Redirector TCP 占用端口
/// </summary>
public int RedirectorTCPPort = 3901;
public ushort RedirectorTCPPort = 3901;
/// <summary>
/// UDP Socket 占用端口
/// </summary>
public int UDPSocketPort = 18291;
public ushort UDPSocketPort = 18291;
/// <summary>
/// HTTP 和 Socks5 本地代理地址
@@ -196,11 +243,19 @@ namespace Netch.Models
/// <summary>
/// 是否使用DLL启动Shadowsocks
/// </summary>
public bool BootShadowsocksFromDLL = false;
public bool BootShadowsocksFromDLL = true;
/// <summary>
/// 语言设置
/// </summary>
public string Language = "System";
public V2rayConfig V2RayConfig = new V2rayConfig();
public AioDNSConfig AioDNS = new AioDNSConfig();
public bool RedirectorSS = false;
public bool ProcessNoProxyForUdp = false;
}
}

View File

@@ -2,18 +2,6 @@
namespace Netch
{
public enum NameList : int
{
TYPE_FILTERLOOPBACK,
TYPE_FILTERTCP,
TYPE_FILTERUDP,
TYPE_TCPHOST,
TYPE_UDPHOST,
TYPE_ADDNAME,
TYPE_BYPNAME,
TYPE_CLRNAME
}
public static class NativeMethods
{
/// <summary>
@@ -66,5 +54,11 @@ namespace Netch
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();
[DllImport("kernel32.dll")]
public static extern bool AllocConsole();
[DllImport("kernel32.dll")]
public static extern bool AttachConsole(int dwProcessId);
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -17,6 +18,14 @@ namespace Netch
[STAThread]
public static void Main(string[] args)
{
if (args.Contains("-console"))
{
if (!NativeMethods.AttachConsole(-1))
{
NativeMethods.AllocConsole();
}
}
// 创建互斥体防止多次运行
using (var mutex = new Mutex(false, "Global\\Netch"))
{

View File

@@ -66,13 +66,13 @@
<ItemGroup>
<PackageReference Include="ILMerge" Version="3.0.41" />
<PackageReference Include="IPNetwork2" Version="2.5.211" />
<PackageReference Include="MaxMind.GeoIP2" Version="3.2.0" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.58" />
<PackageReference Include="MaxMind.GeoIP2" Version="3.3.0" />
<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-preview.8.20407.11" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0-preview.8.20407.11" />
<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.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -153,8 +153,9 @@
"Check update when opened": "打开软件时检查更新",
"Check Beta update": "检查 Beta 更新",
"Update subscribeat when opened": "自动更新订阅",
"SS DLL(No ACL support)": "SS DLL(不支持 ACL",
"SS DLL": "SS DLL",
"Modify System DNS": "修改系统 DNS",
"No Proxy for Udp": "不代理Udp流量",
"ProfileCount": "快捷配置数量",
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试。",
@@ -169,6 +170,7 @@
"Custom ACL": "自定义 ACL 规则",
"Language": "语言",
"Tap Network Sharing": "Tap 网络共享",
"Resolve Server Hostname": "解析服务器主机名",
"Profile": "配置名",
"Profiles": "配置",

View File

@@ -12,7 +12,7 @@ namespace Netch.Servers.Shadowsocks.Models.SSD
/// <summary>
/// 端口
/// </summary>
public int port;
public ushort port;
/// <summary>
/// 加密方式

View File

@@ -10,7 +10,7 @@
/// <summary>
/// 端口
/// </summary>
public int port;
public ushort port;
/// <summary>
/// 加密方式

View File

@@ -3,7 +3,7 @@ namespace Netch.Servers.Shadowsocks.Models
public class ShadowsocksConfig
{
public string server { get; set; }
public int server_port { get; set; }
public ushort server_port { get; set; }
public string password { get; set; }
public string method { get; set; }
public string remarks { get; set; }

View File

@@ -11,23 +11,23 @@ namespace Netch.Servers.Shadowsocks
public override string Name { get; protected set; } = "Shadowsocks";
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
public int? Socks5LocalPort { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(Server s, Mode mode)
{
bool DllFlag()
{
return Global.Settings.BootShadowsocksFromDLL && (mode.Type == 0 || mode.Type == 1 || mode.Type == 2);
}
public bool DllFlag;
public bool Start(in Server s, in Mode mode)
{
var server = (Shadowsocks) s;
DllFlag = Global.Settings.BootShadowsocksFromDLL && mode.Type is 0 or 1 or 2 && !server.HasPlugin();
//从DLL启动Shaowsocks
if (DllFlag())
if (DllFlag)
{
State = State.Starting;
var client = Encoding.UTF8.GetBytes($"{LocalAddress}:{Socks5LocalPort}");
var remote = Encoding.UTF8.GetBytes($"{DNS.Lookup(server.Hostname)}:{server.Port}");
var client = Encoding.UTF8.GetBytes($"{this.LocalAddress()}:{this.Socks5LocalPort()}");
var remote = Encoding.UTF8.GetBytes($"{server.AutoResolveHostname()}:{server.Port}");
var passwd = Encoding.UTF8.GetBytes($"{server.Password}");
var method = Encoding.UTF8.GetBytes($"{server.EncryptMethod}");
if (!ShadowsocksDLL.Info(client, remote, passwd, method))
@@ -55,10 +55,10 @@ namespace Netch.Servers.Shadowsocks
var argument = new StringBuilder();
argument.Append(
$"-s {DNS.Lookup(server.Hostname)} " +
$"-s {server.AutoResolveHostname()} " +
$"-p {server.Port} " +
$"-b {LocalAddress ?? Global.Settings.LocalAddress} " +
$"-l {Socks5LocalPort ?? Global.Settings.Socks5LocalPort} " +
$"-b {this.LocalAddress()} " +
$"-l {this.Socks5LocalPort()} " +
$"-m {server.EncryptMethod} " +
$"-k \"{server.Password}\" " +
"-u ");
@@ -75,13 +75,12 @@ namespace Netch.Servers.Shadowsocks
public override void Stop()
{
if (Instance == null)
if (DllFlag)
ShadowsocksDLL.Stop();
else
StopInstance();
}
private class ShadowsocksDLL
{
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]

View File

@@ -21,7 +21,7 @@ namespace Netch.Servers.Shadowsocks
public string ShortName { get; } = "SS";
public string[] UriScheme { get; } = {"ss", "ssd"};
public Server ParseJObject(JObject j)
public Server ParseJObject(in JObject j)
{
return j.ToObject<Shadowsocks>();
}
@@ -140,7 +140,7 @@ namespace Netch.Servers.Shadowsocks
if (!match.Success) throw new FormatException();
data.Hostname = match.Groups["server"].Value;
data.Port = int.Parse(match.Groups["port"].Value);
data.Port = ushort.Parse(match.Groups["port"].Value);
var base64 = ShareLink.URLSafeBase64Decode(match.Groups["base64"].Value);
match = parser.Match(base64);
@@ -156,7 +156,7 @@ namespace Netch.Servers.Shadowsocks
if (!match.Success) throw new FormatException();
data.Hostname = match.Groups["server"].Value;
data.Port = int.Parse(match.Groups["port"].Value);
data.Port = ushort.Parse(match.Groups["port"].Value);
data.EncryptMethod = match.Groups["method"].Value;
data.Password = match.Groups["password"].Value;
}

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,17 +11,17 @@ namespace Netch.Servers.ShadowsocksR
public override string Name { get; protected set; } = "ShadowsocksR";
public int? Socks5LocalPort { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(Server s, Mode mode)
public bool Start(in Server s, in Mode mode)
{
var server = (ShadowsocksR) s;
#region Argument
var argument = new StringBuilder();
argument.Append($"-s {DNS.Lookup(server.Hostname)} -p {server.Port} -k \"{server.Password}\" -m {server.EncryptMethod} -t 120");
argument.Append($"-s {server.AutoResolveHostname()} -p {server.Port} -k \"{server.Password}\" -m {server.EncryptMethod} -t 120");
if (!string.IsNullOrEmpty(server.Protocol))
{
argument.Append($" -O {server.Protocol}");
@@ -34,7 +34,7 @@ namespace Netch.Servers.ShadowsocksR
if (!string.IsNullOrEmpty(server.OBFSParam)) argument.Append($" -g \"{server.OBFSParam}\"");
}
argument.Append($" -b {LocalAddress ?? Global.Settings.LocalAddress} -l {Socks5LocalPort ?? Global.Settings.Socks5LocalPort} -u");
argument.Append($" -b {this.LocalAddress()} -l {this.Socks5LocalPort()} -u");
if (mode.BypassChina) argument.Append(" --acl default.acl");
#endregion

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;
@@ -17,7 +18,7 @@ namespace Netch.Servers.ShadowsocksR
public string ShortName { get; } = "SR";
public string[] UriScheme { get; } = {"ssr"};
public Server ParseJObject(JObject j)
public Server ParseJObject(in JObject j)
{
return j.ToObject<ShadowsocksR>();
}
@@ -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

@@ -10,6 +10,14 @@ namespace Netch.Servers.Socks5.Form
{
server ??= new Socks5();
Server = server;
CreateTextBox("Username", "Username",
s => true,
s => server.Username = s,
server.Username);
CreateTextBox("Password", "Password",
s => true,
s => server.Password = s,
server.Password);
}
}
}

View File

@@ -0,0 +1,40 @@
using System.IO;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.VMess.Utils;
namespace Netch.Servers.Socks5
{
public class S5Controller : Guard, IServerController
{
public override string Name { get; protected set; } = "Socks5";
public override string MainFile { get; protected set; } = "v2ray.exe";
public bool Start(in Server s, in Mode mode)
{
var server = (Socks5) s;
if (server.Auth())
{
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
if (StartInstanceAuto("-config ..\\data\\last.json"))
{
return true;
}
return false;
}
return true;
}
public override void Stop()
{
if (Instance != null)
StopInstance();
}
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
}
}

View File

@@ -15,7 +15,7 @@ namespace Netch.Servers.Socks5
public string ShortName { get; } = "S5";
public string[] UriScheme { get; } = { };
public Server ParseJObject(JObject j)
public Server ParseJObject(in JObject j)
{
return j.ToObject<Socks5>();
}
@@ -30,15 +30,18 @@ namespace Netch.Servers.Socks5
new Socks5Form().ShowDialog();
}
public string GetShareLink(Server server)
public string GetShareLink(Server s)
{
var server = (Socks5) s;
// https://t.me/socks?server=1.1.1.1&port=443
return $"https://t.me/socks?server={server.Hostname}&port={server.Port}";
return $"https://t.me/socks?server={server.Hostname}&port={server.Port}" +
$"{(!string.IsNullOrWhiteSpace(server.Username) ? $"&user={server.Username}" : "")}" +
$"{(server.Auth() ? $"&user={server.Password}" : "")}";
}
public IServerController GetController()
{
return null;
return new S5Controller();
}
public IEnumerable<Server> ParseUri(string text)
@@ -58,7 +61,7 @@ namespace Netch.Servers.Socks5
var data = new Socks5
{
Hostname = dict["server"],
Port = int.Parse(dict["port"])
Port = ushort.Parse(dict["port"])
};
if (dict.ContainsKey("user") && !string.IsNullOrWhiteSpace(dict["user"]))

View File

@@ -18,5 +18,7 @@ namespace Netch.Servers.Socks5
{
Type = "Socks5";
}
public bool Auth() => !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password);
}
}

View File

@@ -10,6 +10,14 @@ namespace Netch.Servers.Trojan.Form
{
server ??= new Trojan();
Server = server;
CreateTextBox("Password", "Password",
s => true,
s => server.Password = s,
server.Password);
CreateTextBox("Host", "Host",
s => true,
s => server.Host = s,
server.Host);
}
}
}

View File

@@ -18,18 +18,18 @@ namespace Netch.Servers.Trojan
public override string MainFile { get; protected set; } = "Trojan.exe";
public override string Name { get; protected set; } = "Trojan";
public int? Socks5LocalPort { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(Server s, Mode mode)
public bool Start(in Server s, in Mode mode)
{
var server = (Trojan) s;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new TrojanConfig
{
local_addr = LocalAddress ?? Global.Settings.LocalAddress,
local_port = Socks5LocalPort ?? Global.Settings.Socks5LocalPort,
remote_addr = DNS.Lookup(server.Hostname).ToString(),
local_addr = this.LocalAddress(),
local_port = this.Socks5LocalPort(),
remote_addr = server.Hostname,
remote_port = server.Port,
password = new List<string>
{

View File

@@ -17,7 +17,7 @@ namespace Netch.Servers.Trojan
public string ShortName { get; } = "TR";
public string[] UriScheme { get; } = {"trojan"};
public Server ParseJObject(JObject j)
public Server ParseJObject(in JObject j)
{
return j.ToObject<Trojan>();
}
@@ -32,10 +32,10 @@ namespace Netch.Servers.Trojan
new TrojanForm().ShowDialog();
}
public string GetShareLink(Server server)
public string GetShareLink(Server s)
{
// TODO
return "";
var server = (Trojan) s;
return $"trojan://{HttpUtility.UrlEncode(server.Password)}@{server.Hostname}:{server.Port}#{server.Remark}";
}
public IServerController GetController()
@@ -85,7 +85,7 @@ namespace Netch.Servers.Trojan
data.Password = match.Groups["psk"].Value;
data.Hostname = match.Groups["server"].Value;
data.Port = int.Parse(match.Groups["port"].Value);
data.Port = ushort.Parse(match.Groups["port"].Value);
return new[] {data};
}

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
using Netch.Models;
using Netch.Servers.VMess;
namespace Netch.Servers.VLESS
{
public class VLESS : VMess.VMess
{
public VLESS()
{
Type = "VLESS";
}
/// <summary>
/// 加密方式
/// </summary>
public new string EncryptMethod { get; set; } = "none";
/// <summary>
/// 传输协议
/// </summary>
public new string TransferProtocol { get; set; } = VLESSGlobal.TransferProtocols[0];
/// <summary>
/// 伪装类型
/// </summary>
public new string FakeType { get; set; } = VLESSGlobal.FakeTypes[0];
/// <summary>
///
/// </summary>
public string Flow { get; set; }
}
public class VLESSGlobal
{
public static List<string> TransferProtocols => VMessGlobal.TransferProtocols;
public static readonly List<string> FakeTypes = new List<string>
{
"none",
"http"
};
public static readonly List<string> TLSSecure = new List<string>
{
"",
"tls",
"xtls"
};
}
}

View File

@@ -0,0 +1,28 @@
using System.IO;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.VMess.Utils;
namespace Netch.Servers.VLESS
{
public class VLESSController : Guard, IServerController
{
public override string Name { get; protected set; } = "VLESS";
public override string MainFile { get; protected set; } = "v2ray.exe";
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s,in Mode mode)
{
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
return StartInstanceAuto("-config ..\\data\\last.json");
}
public override void Stop()
{
StopInstance();
}
}
}

View File

@@ -0,0 +1,58 @@
using System.Collections.Generic;
using Netch.Forms;
namespace Netch.Servers.VLESS.VLESSForm
{
class VLESSForm : ServerForm
{
protected override string TypeName { get; } = "VLESS";
public VLESSForm(VLESS server = default)
{
server ??= new VLESS();
Server = server;
CreateTextBox("UUID", "UUID",
s => true,
s => server.UserID = s,
server.UserID);
CreateTextBox("EncryptMethod", "Encrypt Method",
s => true,
s => server.EncryptMethod = !string.IsNullOrWhiteSpace(s) ? s : "none",
server.EncryptMethod);
CreateTextBox("Flow", "Flow",
s => true,
s => server.Flow = s,
server.Flow);
CreateComboBox("TransferProtocol", "Transfer Protocol",
VLESSGlobal.TransferProtocols,
s => server.TransferProtocol = s,
server.TransferProtocol);
CreateComboBox("FakeType", "Fake Type",
VLESSGlobal.FakeTypes,
s => server.FakeType = s,
server.FakeType);
CreateTextBox("Host", "Host",
s => true,
s => server.Host = s,
server.Host);
CreateTextBox("Path", "Path",
s => true,
s => server.Path = s,
server.Path);
CreateComboBox("UseMux", "Use Mux",
new List<string> {"", "true", "false"},
s => server.UseMux = s switch
{
"" => null,
"true" => true,
"false" => false,
_ => null
},
server.UseMux?.ToString().ToLower() ?? "");
CreateComboBox("TLSSecure", "TLS Secure",
VLESSGlobal.TLSSecure,
s => server.TLSSecureType = s,
server.TLSSecureType);
}
}
}

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.VLESS
{
public class VLESSUtil : IServerUtil
{
public ushort Priority { get; } = 2;
public string TypeName { get; } = "VLESS";
public string FullName { get; } = "VLESS";
public string ShortName { get; } = "VL";
public string[] UriScheme { get; } = { };
public Server ParseJObject(in JObject j)
{
return j.ToObject<VLESS>();
}
public void Edit(Server s)
{
new VLESSForm.VLESSForm((VLESS) s).ShowDialog();
}
public void Create()
{
new VLESSForm.VLESSForm().ShowDialog();
}
public string GetShareLink(Server server)
{
// TODO
return "";
}
public IServerController GetController()
{
return new VLESSController();
}
public IEnumerable<Server> ParseUri(string text)
{
throw new System.NotImplementedException();
}
public bool CheckServer(Server s)
{
// TODO
return true;
}
}
}

View File

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

View File

@@ -0,0 +1,283 @@
using System.Collections.Generic;
namespace Netch.Servers.VMess.Models
{
public class V2rayConfig
{
public List<Inbounds> inbounds { get; set; }
public List<Outbounds> outbounds { get; set; }
public Routing routing { get; set; }
}
public class Inbounds
{
public string tag { get; set; }
public ushort port { get; set; }
public string listen { get; set; }
public string protocol { get; set; }
public Sniffing sniffing { get; set; }
public Inboundsettings settings { get; set; }
public StreamSettings streamSettings { get; set; }
}
public class Inboundsettings
{
public string auth { get; set; }
public bool udp { get; set; }
public string ip { get; set; }
public string address { get; set; }
public List<UsersItem> clients { get; set; }
public string decryption { get; set; }
}
public class UsersItem
{
public string id { get; set; }
public int alterId { get; set; }
public string email { get; set; }
public string security { get; set; }
public string encryption { get; set; }
public string flow { get; set; }
}
public class Sniffing
{
public bool enabled { get; set; }
public List<string> destOverride { get; set; }
}
public class Outbounds
{
public string tag { get; set; }
public string protocol { get; set; }
public Outboundsettings settings { get; set; }
public StreamSettings streamSettings { get; set; }
public Mux mux { get; set; }
}
public class Outboundsettings
{
public List<VnextItem> vnext { get; set; }
public List<ServersItem> servers { get; set; }
public Response response { get; set; }
}
public class VnextItem
{
public string address { get; set; }
public ushort port { get; set; }
public List<UsersItem> users { get; set; }
}
public class ServersItem
{
public string email { get; set; }
public string address { get; set; }
public string method { get; set; }
public bool ota { get; set; }
public string password { get; set; }
public ushort port { get; set; }
public int level { get; set; }
public List<SocksUsersItem> users { get; set; }
}
public class SocksUsersItem
{
public string user { get; set; }
public string pass { get; set; }
public int level { get; set; }
}
public class Mux
{
public bool enabled { get; set; }
public int concurrency { get; set; }
}
public class Response
{
public string type { get; set; }
}
public class Dns
{
public List<string> servers { get; set; }
}
public class RulesItem
{
public string type { get; set; }
public string port { get; set; }
public List<string> inboundTag { get; set; }
public string outboundTag { get; set; }
public List<string> ip { get; set; }
public List<string> domain { get; set; }
}
public class Routing
{
public string domainStrategy { get; set; }
public List<RulesItem> rules { get; set; }
}
public class StreamSettings
{
public string network { get; set; }
public string security { get; set; }
public TlsSettings tlsSettings { get; set; }
public TcpSettings tcpSettings { get; set; }
public KcpSettings kcpSettings { get; set; }
public WsSettings wsSettings { get; set; }
public HttpSettings httpSettings { get; set; }
public QuicSettings quicSettings { get; set; }
public TlsSettings xtlsSettings { get; set; }
}
public class TlsSettings
{
public bool allowInsecure { get; set; }
public string serverName { get; set; }
}
public class TcpSettings
{
public Header header { get; set; }
}
public class Header
{
public string type { get; set; }
public TCPRequest request { get; set; }
public object response { get; set; }
}
public class TCPRequest
{
public string version = "1.1";
public string method = "GET";
public string path = "/";
public TCPRequestHeaders headers;
}
public class TCPRequestHeaders
{
public string Host;
//public string User_Agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36";
public string Accept_Encoding = "gzip, deflate";
public string Connection = "keep-alive";
public string Pragma = "no-cache";
}
public class KcpSettings
{
public int mtu { get; set; }
public int tti { get; set; }
public int uplinkCapacity { get; set; }
public int downlinkCapacity { get; set; }
public bool congestion { get; set; }
public int readBufferSize { get; set; }
public int writeBufferSize { get; set; }
public Header header { get; set; }
public string seed { get; set; }
}
public class WsSettings
{
public string path { get; set; }
public Headers headers { get; set; }
}
public class Headers
{
public string Host { get; set; }
}
public class HttpSettings
{
public string path { get; set; }
public List<string> host { get; set; }
}
public class QuicSettings
{
public string security { get; set; }
public string key { get; set; }
public Header header { get; set; }
}
}

View File

@@ -3,74 +3,61 @@
/// <summary>
/// 使用 v2rayN 定义的 VMess 链接格式
/// </summary>
public class VMessJObject
public class V2rayNSharing
{
/// <summary>
/// Mux Class
/// </summary>
public class Mux
{
public object enabled;
}
/// <summary>
/// 链接版本
/// </summary>
public string v;
public string v = string.Empty;
/// <summary>
/// 备注
/// </summary>
public string ps;
public string ps = string.Empty;
/// <summary>
/// 地址
/// </summary>
public string add;
public string add = string.Empty;
/// <summary>
/// 端口
/// </summary>
public int port;
public string port = string.Empty;
/// <summary>
/// 用户 ID
/// </summary>
public string id;
public string id = string.Empty;
/// <summary>
/// 额外 ID
/// </summary>
public int aid = 0;
public string aid = string.Empty;
/// <summary>
/// 传输协议
/// </summary>
public string net;
public string net = string.Empty;
/// <summary>
/// 伪装类型
/// </summary>
public string type;
public string type = string.Empty;
/// <summary>
/// 伪装域名HTTPWS
/// </summary>
public string host;
public string host = string.Empty;
/// <summary>
/// 伪装路径
/// </summary>
public string path;
public string path = string.Empty;
/// <summary>
/// 是否使用 TLS
/// </summary>
public string tls;
/// <summary>
/// Mux 多路复用
/// </summary>
public Mux mux;
public string tls = string.Empty;
}
}

View File

@@ -1,206 +0,0 @@
using System.Collections.Generic;
namespace Netch.Servers.VMess.Models
{
public class VMessConfig
{
public class InboundSettings
{
public bool udp = true;
}
public class Inbounds
{
public string listen = "127.0.0.1";
public int port = 2801;
public string protocol = "socks";
public InboundSettings settings;
}
public class User
{
public string id;
public int alterId;
public string security;
}
public class VNext
{
public string address;
public int port;
public List<User> users;
}
public class WSHeaders
{
public string Host;
}
public class TCPRequestHeaders
{
public string Host;
//public string User_Agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36";
public string Accept_Encoding = "gzip, deflate";
public string Connection = "keep-alive";
public string Pragma = "no-cache";
}
public class TCPRequest
{
public string version = "1.1";
public string method = "GET";
public string path = "/";
public TCPRequestHeaders headers;
}
public class TCPHeaders
{
public string type;
public TCPRequest request;
}
public class WebSocketSettings
{
public bool connectionReuse = true;
public string path = "/";
public WSHeaders headers;
}
public class TCPSettings
{
public bool connectionReuse = true;
public TCPHeaders header;
}
public class QUICSettings
{
public string security;
public string key;
public TCPHeaders header;
}
public class KCPSettings
{
public int mtu = 1350;
public int tti = 50;
public int uplinkCapacity = 12;
public int downlinkCapacity = 100;
public bool congestion = false;
public int readBufferSize = 2;
public int writeBufferSize = 2;
public TCPHeaders header;
}
public class HTTPSettings
{
public string host;
public string path;
}
public class TLSSettings
{
public bool allowInsecure = true;
public string serverName;
}
public class OutboundSettings
{
public List<VNext> vnext;
}
public class OutboundMux
{
public bool enabled = false;
}
public class StreamSettings
{
public string network;
public string security;
public TCPSettings tcpSettings;
public WebSocketSettings wsSettings;
public KCPSettings kcpSettings;
public QUICSettings quicSettings;
public HTTPSettings httpSettings;
public TLSSettings tlsSettings;
}
public class Outbounds
{
public string tag = "proxy";
public string protocol = "vmess";
public OutboundSettings settings;
public StreamSettings streamSettings;
public OutboundMux mux;
}
public class RoutingRules
{
public string type = "field";
public List<string> port;
public string outboundTag;
public List<string> ip;
public List<string> domain;
}
public class Routing
{
public string domainStrategy = "IPIfNonMatch";
public List<RoutingRules> rules;
}
public class Config
{
public List<Inbounds> inbounds;
public List<Outbounds> outbounds;
public Routing routing;
}
}
}

View File

@@ -0,0 +1,383 @@
using System.Collections.Generic;
using System.Linq;
using Netch.Models;
using Netch.Servers.VMess.Models;
using Newtonsoft.Json;
using V2rayConfig = Netch.Servers.VMess.Models.V2rayConfig;
namespace Netch.Servers.VMess.Utils
{
public static class V2rayConfigUtils
{
public static string GenerateClientConfig(Server server, Mode mode)
{
try
{
var v2rayConfig = new V2rayConfig();
inbound(server, ref v2rayConfig);
routing(server, mode, ref v2rayConfig);
outbound(server, mode, ref v2rayConfig);
return JsonConvert.SerializeObject(v2rayConfig, Formatting.Indented, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
}
catch
{
return "";
}
}
private static void inbound(Server server, ref V2rayConfig v2rayConfig)
{
try
{
var inbound = new Inbounds
{
port = Global.Settings.Socks5LocalPort,
protocol = "socks",
listen = Global.Settings.LocalAddress,
settings = new Inboundsettings
{
udp = true
}
};
v2rayConfig.inbounds = new List<Inbounds>
{
inbound
};
}
catch
{
// ignored
}
}
private static void routing(Server server, Mode mode, ref V2rayConfig v2rayConfig)
{
try
{
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)
{
switch (mode.Type)
{
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;
}
}
if (mode.Type is 0 or 1 or 2)
{
blockRuleObject.ip.Add("geoip:private");
}
v2rayConfig.routing = new Routing
{
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
{
// ignored
}
}
private static void outbound(Server server, Mode mode, ref V2rayConfig v2rayConfig)
{
try
{
var outbound = new Outbounds
{
settings = new Outboundsettings(),
mux = new Mux(),
streamSettings = new StreamSettings
{
network = "tcp"
}
};
switch (server)
{
case Socks5.Socks5 socks5:
{
outbound.settings.servers = new List<ServersItem>
{
new ServersItem
{
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;
outbound.protocol = "socks";
break;
}
case VLESS.VLESS vless:
{
var vnextItem = new VnextItem
{
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.settings.vnext = new List<VnextItem> {vnextItem};
var usersItem = new UsersItem
{
id = vless.UserID,
alterId = 0,
flow = string.Empty,
encryption = vless.EncryptMethod
};
vnextItem.users.Add(usersItem);
var streamSettings = outbound.streamSettings;
boundStreamSettings(vless, ref streamSettings);
if (vless.TLSSecureType == "xtls")
{
usersItem.flow = string.IsNullOrEmpty(vless.Flow) ? "xtls-rprx-origin" : vless.Flow;
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
}
else
{
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
}
outbound.protocol = "vless";
outbound.settings.servers = null;
break;
}
case VMess vmess:
{
var vnextItem = new VnextItem
{
users = new List<UsersItem>(),
address = server.AutoResolveHostname(),
port = server.Port
};
outbound.settings.vnext = new List<VnextItem> {vnextItem};
var usersItem = new UsersItem
{
id = vmess.UserID,
alterId = vmess.AlterID,
security = vmess.EncryptMethod
};
vnextItem.users.Add(usersItem);
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,
new Outbounds
{
tag = "direct", protocol = "freedom"
},
new Outbounds
{
tag = "block", protocol = "blackhole"
}
};
}
catch
{
// ignored
}
}
private static void boundStreamSettings(VMess server, ref StreamSettings streamSettings)
{
try
{
streamSettings.network = server.TransferProtocol;
if ((streamSettings.security = server.TLSSecureType) != "")
{
var tlsSettings = new TlsSettings
{
allowInsecure = Global.Settings.V2RayConfig.AllowInsecure,
serverName = !string.IsNullOrWhiteSpace(server.Host) ? server.Host : null
};
switch (server.TLSSecureType)
{
case "tls":
streamSettings.tlsSettings = tlsSettings;
break;
case "xtls":
streamSettings.xtlsSettings = tlsSettings;
break;
}
}
switch (server.TransferProtocol)
{
case "kcp":
var kcpSettings = new KcpSettings
{
mtu = Global.Settings.V2RayConfig.KcpConfig.mtu,
tti = Global.Settings.V2RayConfig.KcpConfig.tti,
uplinkCapacity = Global.Settings.V2RayConfig.KcpConfig.uplinkCapacity,
downlinkCapacity = Global.Settings.V2RayConfig.KcpConfig.downlinkCapacity,
congestion = Global.Settings.V2RayConfig.KcpConfig.congestion,
readBufferSize = Global.Settings.V2RayConfig.KcpConfig.readBufferSize,
writeBufferSize = Global.Settings.V2RayConfig.KcpConfig.writeBufferSize,
header = new Header
{
type = server.FakeType
},
seed = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
};
streamSettings.kcpSettings = kcpSettings;
break;
case "ws":
var wsSettings = new WsSettings
{
headers = !string.IsNullOrWhiteSpace(server.Host)
? new Headers {Host = server.Host}
: null,
path = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
};
streamSettings.wsSettings = wsSettings;
break;
case "h2":
var httpSettings = new HttpSettings
{
host = new List<string>
{
string.IsNullOrWhiteSpace(server.Host) ? server.Hostname : server.Host
},
path = server.Path
};
streamSettings.httpSettings = httpSettings;
break;
case "quic":
var quicSettings = new QuicSettings
{
security = server.Host,
key = server.Path,
header = new Header
{
type = server.FakeType
}
};
if (server.TLSSecureType != "")
{
// tls or xtls
streamSettings.tlsSettings.serverName = server.Hostname;
}
streamSettings.quicSettings = quicSettings;
break;
default:
if (server.FakeType == "http")
{
var tcpSettings = new TcpSettings
{
header = new Header
{
type = server.FakeType,
request = new TCPRequest
{
path = string.IsNullOrWhiteSpace(server.Path) ? "/" : server.Path,
headers = new TCPRequestHeaders
{
Host = string.IsNullOrWhiteSpace(server.Host) ? server.Hostname : server.Host
}
}
}
};
streamSettings.tcpSettings = tcpSettings;
}
break;
}
}
catch
{
// ignored
}
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Netch.Models;
@@ -64,12 +65,12 @@ namespace Netch.Servers.VMess
/// <summary>
/// TLS 底层传输安全
/// </summary>
public bool TLSSecure { get; set; } = false;
public string TLSSecureType { get; set; } = VMessGlobal.TLSSecure[0];
/// <summary>
/// Mux 多路复用
/// </summary>
public bool UseMux { get; set; } = true;
public bool? UseMux { get; set; } = true;
}
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

@@ -1,10 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.IO;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.VMess.Models;
using Netch.Utils;
using Newtonsoft.Json;
using Netch.Servers.VMess.Utils;
namespace Netch.Servers.VMess
{
@@ -16,171 +13,16 @@ 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 int? Socks5LocalPort { get; set; }
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(Server s, Mode mode)
public bool Start(in Server s,in Mode mode)
{
var server = (VMess) s;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new VMessConfig.Config()
{
inbounds = new List<VMessConfig.Inbounds>
{
new VMessConfig.Inbounds
{
settings = new VMessConfig.InboundSettings(),
port = Socks5LocalPort ?? Global.Settings.Socks5LocalPort,
listen = LocalAddress ?? Global.Settings.LocalAddress
}
},
outbounds = new List<VMessConfig.Outbounds>
{
new VMessConfig.Outbounds
{
settings = new VMessConfig.OutboundSettings
{
vnext = new List<VMessConfig.VNext>
{
new VMessConfig.VNext
{
address = DNS.Lookup(server.Hostname).ToString(),
port = server.Port,
users = new List<VMessConfig.User>
{
new VMessConfig.User
{
id = server.UserID,
alterId = server.AlterID,
security = server.EncryptMethod
}
}
}
}
},
streamSettings = new VMessConfig.StreamSettings
{
network = server.TransferProtocol,
security = server.TLSSecure ? "tls" : string.Empty,
wsSettings = server.TransferProtocol == "ws"
? new VMessConfig.WebSocketSettings
{
path = server.Path == string.Empty ? "/" : server.Path,
headers = new VMessConfig.WSHeaders
{
Host = server.Host == string.Empty ? server.Hostname : server.Host
}
}
: null,
tcpSettings = server.FakeType == "http"
? new VMessConfig.TCPSettings
{
header = new VMessConfig.TCPHeaders
{
type = server.FakeType,
request = new VMessConfig.TCPRequest
{
path = server.Path == string.Empty ? "/" : server.Path,
headers = new VMessConfig.TCPRequestHeaders
{
Host = server.Host == string.Empty ? server.Hostname : server.Host
}
}
}
}
: null,
kcpSettings = server.TransferProtocol == "kcp"
? new VMessConfig.KCPSettings
{
header = new VMessConfig.TCPHeaders
{
type = server.FakeType
}
}
: null,
quicSettings = server.TransferProtocol == "quic"
? new VMessConfig.QUICSettings
{
security = server.QUICSecure,
key = server.QUICSecret,
header = new VMessConfig.TCPHeaders
{
type = server.FakeType
}
}
: null,
httpSettings = server.TransferProtocol == "h2"
? new VMessConfig.HTTPSettings
{
host = server.Host == "" ? server.Hostname : server.Host,
path = server.Path == "" ? "/" : server.Path
}
: null,
tlsSettings = new VMessConfig.TLSSettings
{
allowInsecure = true,
serverName = server.Host == "" ? server.Hostname : server.Host
}
},
mux = new VMessConfig.OutboundMux
{
enabled = server.UseMux
}
},
mode.Type == 0 || mode.Type == 1 || mode.Type == 2
? new VMessConfig.Outbounds
{
tag = "TUNTAP",
protocol = "freedom"
}
: new VMessConfig.Outbounds
{
tag = "direct",
protocol = "freedom"
}
},
routing = new VMessConfig.Routing
{
rules = new List<VMessConfig.RoutingRules>
{
mode.BypassChina
? new VMessConfig.RoutingRules
{
type = "field",
ip = new List<string>
{
"geoip:cn",
"geoip:private"
},
domain = new List<string>
{
"geosite:cn"
},
outboundTag = "direct"
}
: new VMessConfig.RoutingRules
{
type = "field",
ip = new List<string>
{
"geoip:private"
},
outboundTag = "direct"
}
}
}
}));
if (StartInstanceAuto("-config ..\\data\\last.json"))
{
if (File.Exists("data\\last.json")) File.Delete("data\\last.json");
return true;
}
return false;
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
return StartInstanceAuto("-config ..\\data\\last.json");
}
public override void Stop()

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
@@ -17,7 +18,7 @@ namespace Netch.Servers.VMess
public string ShortName { get; } = "V2";
public string[] UriScheme { get; } = {"vmess"};
public Server ParseJObject(JObject j)
public Server ParseJObject(in JObject j)
{
return j.ToObject<VMess>();
}
@@ -48,7 +49,7 @@ namespace Netch.Servers.VMess
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecure ? "tls" : ""
tls = server.TLSSecureType
});
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
}
@@ -63,26 +64,25 @@ namespace Netch.Servers.VMess
var data = new VMess();
text = text.Substring(8);
var vmess = JsonConvert.DeserializeObject<VMessJObject>(ShareLink.URLSafeBase64Decode(text));
V2rayNSharing vmess;
try
{
vmess = JsonConvert.DeserializeObject<V2rayNSharing>(ShareLink.URLSafeBase64Decode(text));
}
catch (Exception e)
{
Logging.Warning(e.ToString());
return null;
}
data.Remark = vmess.ps;
data.Hostname = vmess.add;
data.Port = vmess.port;
data.Port = ushort.Parse(vmess.port);
data.UserID = vmess.id;
data.AlterID = vmess.aid;
data.AlterID = int.Parse(vmess.aid);
data.TransferProtocol = vmess.net;
data.FakeType = vmess.type;
if (vmess.v == null || vmess.v == "1")
{
var info = vmess.host.Split(';');
if (info.Length == 2)
{
vmess.host = info[0];
vmess.path = info[1];
}
}
if (data.TransferProtocol == "quic")
{
if (VMessGlobal.QUIC.Contains(vmess.host))
@@ -97,29 +97,9 @@ namespace Netch.Servers.VMess
data.Path = vmess.path;
}
data.TLSSecure = vmess.tls == "tls";
if (vmess.mux == null)
{
data.UseMux = false;
}
else
{
if (vmess.mux.enabled is bool enabled)
{
data.UseMux = enabled;
}
else if (vmess.mux.enabled is string muxEnabled)
{
data.UseMux = muxEnabled == "true"; // 针对使用字符串当作布尔值的情况
}
else
{
data.UseMux = false;
}
}
data.TLSSecureType = vmess.tls;
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
return CheckServer(data) ? new[] {data} : null;
}

View File

@@ -7,6 +7,8 @@ using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
namespace Netch.Utils
{
@@ -52,7 +54,7 @@ namespace Netch.Utils
/// <summary>
/// 根据程序名统计流量
/// </summary>
public static void NetTraffic(Server server, Mode mode)
public static void NetTraffic(in Server server, in Mode mode)
{
if (!Global.Flags.IsWindows10Upper)
return;
@@ -62,24 +64,35 @@ 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);
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;
}
else if (server.Type.Equals("SS") && Global.Settings.BootShadowsocksFromDLL &&
(mode.Type == 0 || mode.Type == 1 || mode.Type == 2))
if (!instances.Any())
{
instances.Add(Process.GetCurrentProcess());
}
else if (MainController.ServerController != null)
{
if (MainController.ServerController is Guard instanceController)
instances.Add(instanceController.Instance);
}
else if (MainController.ModeController != null)
{
if (MainController.ModeController is Guard instanceController)
instances.Add(instanceController.Instance);
switch (MainController.ModeController)
{
case null:
break;
case HTTPController httpController:
instances.Add(httpController.pPrivoxyController.Instance);
break;
case NFController _:
instances.Add(Process.GetCurrentProcess());
break;
case Guard instanceController:
instances.Add(instanceController.Instance);
break;
}
}
var processList = instances.Select(instance => instance.Id).ToList();

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;
@@ -49,6 +51,8 @@ namespace Netch.Utils
private static RegistryKey AdapterRegistry(bool write = false)
{
if (Global.Outbound.Adapter == null)
Utils.SearchOutboundAdapter();
return Registry.LocalMachine.OpenSubKey(
$@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Global.Outbound.Adapter.Id}", write);
}
@@ -73,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

@@ -9,23 +9,44 @@ namespace Netch.Utils
{
public static class ICSHelper
{
public static bool Enabled
public static bool? Enabled
{
get
{
TUNTAPController.SearchTapAdapter();
return (
from NetworkConnection connection in new NetworkConnectionCollection()
where connection.DeviceName == Global.TUNTAP.Adapter.Description
select connection.SharingEnabled
).FirstOrDefault();
AutoSearchTapAdapter();
if (Global.TUNTAP.Adapter == null)
return null;
foreach (NetworkConnection connection in new NetworkConnectionCollection())
{
try
{
if (connection.DeviceName == Global.TUNTAP.Adapter?.Description)
{
return connection.SharingEnabled;
}
}
catch (Exception e)
{
Logging.Warning(e.ToString());
}
}
return null;
}
}
private static void AutoSearchTapAdapter()
{
if (Global.TUNTAP.Adapter == null)
TUNTAPController.SearchTapAdapter();
}
public static bool Enable()
{
Utils.SearchOutboundAdapter(false);
TUNTAPController.SearchTapAdapter();
AutoSearchTapAdapter();
if (Global.TUNTAP.Adapter == null || Global.Outbound.Adapter == null)
{
@@ -133,9 +154,19 @@ namespace Netch.Utils
public static void Disable()
{
foreach (var connection in new NetworkConnectionCollection().Cast<NetworkConnection>().Where(connection => connection.SharingEnabled))
foreach (NetworkConnection connection in new NetworkConnectionCollection())
{
connection.DisableSharing();
try
{
if (connection.SharingEnabled)
{
connection.DisableSharing();
}
}
catch (Exception e)
{
Logging.Warning(e.ToString());
}
}
CleanupWMISharingEntries();

View File

@@ -2,7 +2,11 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Netch.Controllers;
using Netch.Forms;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
namespace Netch.Utils
{
@@ -60,21 +64,23 @@ namespace Netch.Utils
for (var i = 0; i < content.Length; i++)
{
var text = content[i];
var text = content[i].Trim();
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
{
@@ -83,8 +89,7 @@ namespace Netch.Utils
}
else
{
if (!text.StartsWith("#") && !string.IsNullOrWhiteSpace(text))
mode.Rule.Add(text.Trim());
mode.Rule.Add(text);
}
}
@@ -133,5 +138,55 @@ namespace Netch.Utils
Global.Modes.Remove(mode);
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;
port = null;
portName = string.Empty;
portType = PortType.Both;
switch (type)
{
case 0:
modeController = new NFController();
port = Global.Settings.RedirectorTCPPort;
portName = "Redirector TCP";
break;
case 1:
case 2:
modeController = new TUNTAPController();
break;
case 3:
case 5:
modeController = new HTTPController();
port = Global.Settings.HTTPLocalPort;
portName = "HTTP";
MainForm.StatusPortInfoText.HttpPort = (ushort) port;
break;
case 4:
modeController = null;
break;
default:
Logging.Error("未知模式类型");
throw new StartFailedException();
}
return modeController;
}
}
}

View File

@@ -8,8 +8,8 @@ namespace Netch.Utils
{
public static class PortHelper
{
private static readonly List<int[]> TCPExcludedRanges = new List<int[]>();
private static readonly List<int[]> UDPExcludedRanges = new List<int[]>();
private static readonly List<ushort[]> TCPExcludedRanges = new List<ushort[]>();
private static readonly List<ushort[]> UDPExcludedRanges = new List<ushort[]>();
static PortHelper()
{
@@ -24,7 +24,7 @@ namespace Netch.Utils
}
}
private static void GetExcludedPortRange(PortType portType, ref List<int[]> targetList)
private static void GetExcludedPortRange(PortType portType, ref List<ushort[]> targetList)
{
var lines = new List<string>();
var process = new Process
@@ -63,9 +63,9 @@ namespace Netch.Utils
var value = line.Trim().Split(' ').Where(s => s != string.Empty);
var port = 0;
ushort port = 0;
var _ = (from s1 in value
where int.TryParse(s1, out port)
where ushort.TryParse(s1, out port)
select port).ToArray();
targetList.Add(_);
@@ -80,7 +80,7 @@ namespace Netch.Utils
/// <param name="type">端口类型</param>
/// <returns>是否是保留端口</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
private static bool IsPortExcluded(int port, PortType type)
private static bool IsPortExcluded(ushort port, PortType type)
{
return type switch
{
@@ -97,7 +97,7 @@ namespace Netch.Utils
/// <param name="port">端口</param>
/// <param name="type">检查端口类型</param>
/// <returns>是否被占用</returns>
public static bool PortInUse(int port, PortType type = PortType.Both)
public static bool PortInUse(ushort port, PortType type = PortType.Both)
{
var netInfo = IPGlobalProperties.GetIPGlobalProperties();
var isTcpUsed = type != PortType.UDP &&
@@ -111,11 +111,12 @@ namespace Netch.Utils
return isPortExcluded && (isTcpUsed || isUdpUsed);
}
public static int GetAvailablePort()
public static ushort GetAvailablePort()
{
for (var i = 0; i < 55535; i++)
var random = new Random();
for (ushort i = 0; i < 55535; i++)
{
var p = new Random().Next(10000, 65535);
var p = (ushort) random.Next(10000, 65535);
if (!PortInUse(p))
{
return p;
@@ -128,7 +129,7 @@ namespace Netch.Utils
/// <summary>
/// 记录Netch使用的端口
/// </summary>
public static readonly List<int> UsingPorts = new List<int>();
public static readonly List<ushort> UsingPorts = new List<ushort>();
}
/// <summary>

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;
@@ -120,48 +121,36 @@ namespace Netch.Utils
}
var list = new List<Server>();
try
{
try
list.AddRange(JsonConvert.DeserializeObject<List<ShadowsocksConfig>>(text).Select(server => new Shadowsocks
{
list.AddRange(JsonConvert.DeserializeObject<List<ShadowsocksConfig>>(text).Select(server => new Shadowsocks
{
Hostname = server.server,
Port = server.server_port,
EncryptMethod = server.method,
Password = server.password,
Remark = server.remarks,
Plugin = server.plugin,
PluginOption = server.plugin_opts
}));
}
catch (JsonReaderException)
Hostname = server.server,
Port = server.server_port,
EncryptMethod = server.method,
Password = server.password,
Remark = server.remarks,
Plugin = server.plugin,
PluginOption = server.plugin_opts
}));
}
catch (JsonReaderException)
{
foreach (var line in text.GetLines())
{
foreach (var line in text.GetLines())
{
var servers = ParseUri(line);
if (servers != null)
{
list.AddRange(servers);
}
}
}
if (list.Count == 0)
{
return null;
list.AddRange(ParseUri(line));
}
}
catch (Exception e)
{
Logging.Error(e.ToString());
return null;
}
return list;
}
private static IEnumerable<Server> ParseUri(string text)
private static IEnumerable<Server> ParseUri(in string text)
{
var list = new List<Server>();
@@ -179,19 +168,19 @@ namespace Netch.Utils
{
var scheme = GetUriScheme(text);
var util = ServerHelper.GetUtilByUriScheme(scheme);
if (util == null)
if (util != null)
{
list.AddRange(util.ParseUri(text));
}
else
{
Logging.Warning($"无法处理 {scheme} 协议订阅链接");
return null;
}
list.AddRange(util.ParseUri(text));
}
}
catch (Exception e)
{
Logging.Error(e.ToString());
return null;
}
foreach (var node in list)
@@ -212,31 +201,41 @@ namespace Netch.Utils
private static Server ParseNetchUri(string text)
{
text = text.Substring(8);
var NetchLink = (JObject) JsonConvert.DeserializeObject(URLSafeBase64Decode(text));
if (NetchLink == null)
try
{
text = text.Substring(8);
var NetchLink = (JObject) JsonConvert.DeserializeObject(URLSafeBase64Decode(text));
if (NetchLink == null)
{
return null;
}
if (string.IsNullOrEmpty((string) NetchLink["Hostname"]))
{
return null;
}
if (!ushort.TryParse((string) NetchLink["Port"], out _))
{
return null;
}
var type = (string) NetchLink["Type"];
var s = ServerHelper.GetUtilByTypeName(type).ParseJObject(NetchLink);
return ServerHelper.GetUtilByTypeName(s.Type).CheckServer(s) ? s : null;
}
catch (Exception e)
{
Logging.Warning(e.ToString());
return null;
}
if (string.IsNullOrEmpty((string) NetchLink["Hostname"]))
{
return null;
}
if (!ushort.TryParse((string) NetchLink["Port"], out _))
{
return null;
}
var type = (string) NetchLink["Type"];
var s = ServerHelper.GetUtilByTypeName(type).ParseJObject(NetchLink);
return ServerHelper.GetUtilByTypeName(s.Type).CheckServer(s) ? s : null;
}
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}));
}
}
}

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)
@@ -96,7 +98,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"));
}
@@ -126,47 +128,38 @@ namespace Netch.Utils
public static string GetFileVersion(string file) => File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
public static bool SearchOutboundAdapter(bool log = true)
public static bool SearchOutboundAdapter(bool logging = true)
{
IPAddress localEnd;
try
{
localEnd = WebUtil.BestLocalEndPoint(new IPEndPoint(0x72727272, 53)).Address;
}
catch
// 寻找出口适配器
if (Win32Native.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0),
0, out var pRoute) != 0)
{
Logging.Error("GetBestRoute 搜索失败");
return false;
}
Global.Outbound.Index = pRoute.dwForwardIfIndex;
// 根据 IP Index 寻找 出口适配器
try
{
// 根据 IP 寻找 出口适配器
Global.Outbound.Adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ =>
var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ =>
{
try
{
return _.GetIPProperties().UnicastAddresses.Any(ip =>
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork && ip.Address.ToString().Equals(localEnd.ToString()))
{
Global.Outbound.Index = _.GetIPProperties().GetIPv4Properties().Index;
return true;
}
return false;
});
return _.GetIPProperties().GetIPv4Properties().Index == Global.Outbound.Index;
}
catch
{
return false;
}
});
Global.Outbound.Gateway = Global.Outbound.Adapter.GetIPProperties().GatewayAddresses[0].Address;
if (log)
Global.Outbound.Adapter = adapter;
Global.Outbound.Gateway = new IPAddress(pRoute.dwForwardNextHop);
if (logging)
{
Logging.Info($"出口 IPv4 地址:{Global.Outbound.Address}");
Logging.Info($"出口 网关 地址:{Global.Outbound.Gateway}");
Logging.Info($"出口适配器:{Global.Outbound.Adapter.Name} {Global.Outbound.Adapter.Id} {Global.Outbound.Adapter.Description}, index: {Global.Outbound.Index}");
Logging.Info($"出口适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.Outbound.Index}");
}
return true;
@@ -206,7 +199,7 @@ namespace Netch.Utils
}
}
public static void ComponentIterator(Component component, Action<Component> func)
public static void ComponentIterator(in Component component, in Action<Component> func)
{
func.Invoke(component);
switch (component)
@@ -246,5 +239,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 | SecurityProtocolType.Tls13;
}
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

@@ -106,7 +106,7 @@ namespace Netch.Utils
return translateFile;
}
public static void TranslateForm(Control c)
public static void TranslateForm(in Control c)
{
Utils.ComponentIterator(c, component =>
{

View File

@@ -1,11 +1,347 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Text;
namespace Netch
{
public static class Win32Native
{
public enum ForwardType
{
Other = 1,
Invalid = 2,
Direct = 3,
Indirect = 4
}
public enum ForwardProtocol
{
Other = 1,
Local = 2,
NetMGMT = 3,
ICMP = 4,
EGP = 5,
GGP = 6,
Hello = 7,
RIP = 8,
IS_IS = 9,
ES_IS = 10, // 0x0000000A
CISCO = 11, // 0x0000000B
BBN = 12, // 0x0000000C
OSPF = 13, // 0x0000000D
BGP = 14, // 0x0000000E
NT_AUTOSTATIC = 10002, // 0x00002712
NT_STATIC = 10006, // 0x00002716
NT_STATIC_NON_DOD = 10007 // 0x00002717
}
public class RouteEntry
{
internal MIB_IPFORWARDROW _ipFwdNative;
private int _metric1;
private int _metric2;
private int _metric3;
private int _metric4;
private int _metric5;
private IPAddress _destination;
private IPAddress _mask;
private int _policy;
private IPAddress _nextHop;
private NetworkInterface _interface;
private ForwardProtocol _protocol;
private ForwardType _type;
private int _nextHopAS;
private int _age;
private int _index;
public int Index
{
get => _index;
set => _index = value;
}
public IPAddress Destination
{
get => _destination;
set => _destination = value;
}
public IPAddress Mask
{
get => _mask;
set => _mask = value;
}
public int Policy
{
get => _policy;
set => _policy = value;
}
public IPAddress NextHop
{
get => _nextHop;
set => _nextHop = value;
}
public NetworkInterface RelatedInterface => _interface;
public string InterfaceName
{
get
{
if (RelatedInterface == null)
return string.Empty;
return RelatedInterface.Name;
}
}
public ForwardType ForwardType
{
get => _type;
set => _type = value;
}
public ForwardProtocol Protocol
{
get => _protocol;
set => _protocol = value;
}
public int Age
{
get => _age;
set => _age = value;
}
public int NextHopAS
{
get => _nextHopAS;
set => _nextHopAS = value;
}
public int Metric1
{
get => _metric1;
set => _metric1 = value;
}
public int Metric2
{
get => _metric2;
set => _metric2 = value;
}
public int Metric3
{
get => _metric3;
set => _metric3 = value;
}
public int Metric4
{
get => _metric4;
set => _metric4 = value;
}
public int Metric5
{
get => _metric5;
set => _metric5 = value;
}
public RouteEntry(
uint destination,
uint mask,
int policy,
uint nextHop,
NetworkInterface intf,
ForwardType type,
ForwardProtocol proto,
int age,
int nextHopAS,
int metric1,
int metric2,
int metric3,
int metric4,
int metric5,
int idx)
{
_age = age;
_policy = policy;
_protocol = proto;
_type = type;
_destination = new IPAddress(destination);
_mask = new IPAddress(mask);
_nextHop = new IPAddress(nextHop);
_nextHopAS = nextHopAS;
_interface = intf;
_metric1 = metric1;
_metric2 = metric2;
_metric3 = metric3;
_metric4 = metric4;
_metric5 = metric5;
_index = idx;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MIB_IFROW
{
private const int MAX_INTERFACE_NAME_LEN = 256;
private const int MAXLEN_IFDESCR = 256;
private const int MAXLEN_PHYSADDR = 8;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string wszName;
public int dwIndex;
public int dwType;
public int dwMtu;
public int dwSpeed;
public int dwPhysAddrLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] bPhysAddr;
public int dwAdminStatus;
public int dwOperStatus;
public int dwLastChange;
public int dwInOctets;
public int dwInUcastPkts;
public int dwInNUcastPkts;
public int dwInDiscards;
public int dwInErrors;
public int dwInUnknownProtos;
public int dwOutOctets;
public int dwOutUcastPkts;
public int dwOutNUcastPkts;
public int dwOutDiscards;
public int dwOutErrors;
public int dwOutQLen;
public int dwDescrLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] bDescr;
}
public class AdaptersTable
{
private Dictionary<int, NetworkInterface> _adapters = new Dictionary<int, NetworkInterface>();
public IDictionary<int, NetworkInterface> GetAdapters()
{
return _adapters;
}
public NetworkInterface GetAdapter(int interfaceIndex)
{
NetworkInterface networkInterface = null;
_adapters.TryGetValue(interfaceIndex, out networkInterface);
return networkInterface;
}
public int GetAdapterIndex(NetworkInterface networkInterface)
{
return _adapters.First(a => a.Value == networkInterface).Key;
}
public AdaptersTable()
{
var num1 = IntPtr.Zero;
var pdwSize = 0;
var num2 = 0;
num2 = GetIfTable(IntPtr.Zero, ref pdwSize, true);
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
try
{
num1 = Marshal.AllocHGlobal(pdwSize);
if (GetIfTable(num1, ref pdwSize, true) != 0)
return;
var num3 = Marshal.ReadInt32(num1);
var ptr = new IntPtr(num1.ToInt32() + 4);
for (var index = 0; index < num3; ++index)
{
var structure = (MIB_IFROW)Marshal.PtrToStructure(ptr, typeof(MIB_IFROW));
var pIfRow = new MIB_IFROW();
pIfRow.dwIndex = structure.dwIndex;
if (GetIfEntry(ref pIfRow) == 0)
{
var str = Encoding.ASCII.GetString(structure.bDescr, 0, pIfRow.dwDescrLen - 1);
foreach (var networkInterface in networkInterfaces)
{
if (networkInterface.Description == str)
{
_adapters.Add(structure.dwIndex, networkInterface);
break;
}
}
}
ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(MIB_IFROW)));
}
}
catch (Exception)
{
// ignored
}
finally
{
Marshal.FreeHGlobal(num1);
}
}
}
public struct MIB_IPFORWARDROW
{
public uint dwForwardDest;
public uint dwForwardMask;
public int dwForwardPolicy;
public uint dwForwardNextHop;
public int dwForwardIfIndex;
public ForwardType dwForwardType;
public ForwardProtocol dwForwardProto;
public int dwForwardAge;
public int dwForwardNextHopAS;
public int dwForwardMetric1;
public int dwForwardMetric2;
public int dwForwardMetric3;
public int dwForwardMetric4;
public int dwForwardMetric5;
public static implicit operator MIB_IPFORWARDROW(RouteEntry value)
{
var mibIpforwardrow = new MIB_IPFORWARDROW();
mibIpforwardrow.dwForwardAge = value.Age;
mibIpforwardrow.dwForwardDest = BitConverter.ToUInt32(value.Destination.GetAddressBytes(), 0);
mibIpforwardrow.dwForwardMask = BitConverter.ToUInt32(value.Mask.GetAddressBytes(), 0);
mibIpforwardrow.dwForwardMetric1 = value.Metric1;
mibIpforwardrow.dwForwardMetric2 = value.Metric2;
mibIpforwardrow.dwForwardMetric3 = value.Metric3;
mibIpforwardrow.dwForwardMetric4 = value.Metric4;
mibIpforwardrow.dwForwardMetric5 = value.Metric5;
mibIpforwardrow.dwForwardNextHop = BitConverter.ToUInt32(value.NextHop.GetAddressBytes(), 0);
mibIpforwardrow.dwForwardNextHopAS = value.NextHopAS;
mibIpforwardrow.dwForwardPolicy = value.Policy;
mibIpforwardrow.dwForwardProto = value.Protocol;
mibIpforwardrow.dwForwardType = value.ForwardType;
var adaptersTable = new AdaptersTable();
mibIpforwardrow.dwForwardIfIndex = adaptersTable.GetAdapterIndex(value.RelatedInterface);
return mibIpforwardrow;
}
}
[DllImport("iphlpapi", SetLastError = true)]
public static extern int GetIfTable(IntPtr pIfTable, ref int pdwSize, bool bOrder);
[DllImport("iphlpapi", SetLastError = true)]
public static extern int GetIfEntry(ref MIB_IFROW pIfRow);
[DllImport("iphlpapi", SetLastError = true)]
public static extern int GetBestRoute(uint dwDestAddr, int dwSourceAddr, out MIB_IPFORWARDROW pRoute);
[DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("WinINet")]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
}
}
}

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

@@ -86,7 +86,7 @@ namespace NetchUpdater
Process.Start(new ProcessStartInfo
{
FileName = newUpdaterPath,
Arguments = $"{port} {updatePath} {targetPath}",
Arguments = $"{port} \"{updatePath}\" \"{targetPath}\"",
WorkingDirectory = tempPath,
UseShellExecute = false
});
@@ -98,9 +98,9 @@ namespace NetchUpdater
#endregion
/*while (!Debugger.IsAttached)
/*Console.WriteLine("Waiting Attach");
while (!Debugger.IsAttached)
{
Console.WriteLine("Waiting Attach");
Thread.Sleep(1000);
}*/
@@ -221,7 +221,7 @@ namespace NetchUpdater
File.WriteAllBytes("7za.exe", Resources._7za);
var argument = new StringBuilder();
argument.Append($" x {archiveFileName} -o{destDirName} ");
argument.Append($" x \"{archiveFileName}\" -o\"{destDirName}\" ");
if (overwrite)
argument.Append(" -y ");

View File

@@ -1,17 +1,18 @@
# Netch
[![Group](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/Netch_Discuss_Group)
[![Channel](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/Netch)
[![Platform](https://img.shields.io/badge/platform-windows-orange.svg)](https://github.com/NetchX/Netch)
[![Version](https://img.shields.io/github/v/release/NetchX/Netch)](https://github.com/NetchX/Netch/releases)
[![Downloads](https://img.shields.io/github/downloads/NetchX/Netch/total.svg)](https://github.com/NetchX/Netch/releases)
[![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)](https://github.com/NetchX/Netch/actions)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
[![](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/Netch) [![](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/Netch_Discuss_Group)
[![Website](https://img.shields.io/website?url=https%3A%2F%2Fnetch.org)](https://netch.org/)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
[中文说明](/docs/README.zh-CN.md)
[FAQ/常见问题](https://netch.org/#/docs/zh-CN/faq)
[常见问题](https://netch.org/#/docs/zh-CN/faq)
Game accelerator
Game network accelerator
## TOC
- [Netch](#netch)
@@ -23,19 +24,24 @@ Game accelerator
- [Requirements](#requirements)
## Description
Netch is an open source game network accelerator. Unlike SSTap, which needs to add rules to function as a blacklist proxy, Netch is more similar to SocksCap64, which can scan the game directory to get their process names specifically and forward their network traffic through the proxy server
Netch is an open source game accelerator. Unlike SSTap, which needs to add rules to function as a blacklist proxy, Netch is more similar to SocksCap64, which can scan the game directory to get their process names specifically and forward their network traffic through the proxy server. Now supports Socks5, Shadowsocks, ShadowsocksR, VMess.
Currently supports the following protocols
- Socks5
- Shadowsocks
- ShadowsocksR
- Trojan
- VMess
- VLess
As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an NATTypeTester to test out what your NAT type is. When using SSTap to speed up some P2P gaming connections or the game is required for that kind of open NAT type, you may experience some bad situations such as unable to join the game.
As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an NATTypeTester to test out what your NAT type is. When using SSTap to speed up some P2P gaming connections or the game is required for that kind of open NAT type, you may experience some bad situations such as unable to join the game
## Sponsor
<a href="https://www.jetbrains.com/?from=Netch"><img src=".github/jetbrains-variant-4.svg" alt="JetBrains" width="200"/></a>
- [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*
@@ -58,8 +64,9 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [unbound](https://github.com/NLnetLabs/unbound)
- [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

@@ -1,35 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Test")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("53397641-35CA-4336-8E22-2CE12EF476AC")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,64 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{53397641-35CA-4336-8E22-2CE12EF476AC}</ProjectGuid>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Test</RootNamespace>
<AssemblyName>Test</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb">
<HintPath>..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Tests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Netch\Netch.csproj">
<Project>{4b041b91-5790-4571-8c58-c63ffe4bc9f8}</Project>
<Name>Netch</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<Platforms>x64</Platforms>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove=".gitignore" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Netch\Netch.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.12.0" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,5 @@
using System.Linq;
using System.Windows.Forms;
using Netch.Servers.ShadowsocksR.Form;
using Netch.Servers.ShadowsocksR;
using Netch.Servers.VMess;
using Netch.Servers.VMess.Form;

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="3.5.0" targetFramework="net45" />
</packages>

View File

@@ -206,10 +206,6 @@ ping 的值未必准确,因为这只是你本地到代理服务器而非游戏
如果需要 SteamUplay 等启动器也被代理,参照前面的方式对 SteamUplay 根目录也进行扫描即可
如果出现了启动失败,或者无法代理成功的情况,请先尝试`选项 - 重启服务``选项 - 卸载服务`,或者在退出 Netch 以后,点击运行在 Netch 根目录下的 `DriverUpdater.exe` 程序进行驱动更新
## 语言支持
Netch 支持多种语言,在启动时会根据系统语言选择自身语言。如果需要手动切换语言,可以在启动时加入命令行参数,命令行参数为目前支持的语言代码,可以去 [NetchTranslation/i18n](https://github.com/NetchX/NetchTranslation/tree/master/i18n) 文件夹下查看外部支持的语言代码文件。Netch 目前内置 en-USzh-CN外置 zh-TW。欢迎大家为 [NetchTranslation](https://github.com/NetchX/NetchTranslation) 提供其他语言的翻译

View File

@@ -1,5 +1,12 @@
# Netch
[![](https://img.shields.io/badge/Telegram-频道-blue)](https://t.me/Netch) [![](https://img.shields.io/badge/Telegram-讨论组-green)](https://t.me/Netch_Discuss_Group) ![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)
[![群组](https://img.shields.io/badge/Telegram-群组-green)](https://t.me/Netch_Discuss_Group)
[![频道](https://img.shields.io/badge/Telegram-频道-blue)](https://t.me/Netch)
[![平台](https://img.shields.io/badge/平台-windows-orange.svg)](https://github.com/NetchX/Netch)
[![版本](https://img.shields.io/github/v/release/NetchX/Netch)](https://github.com/NetchX/Netch/releases)
[![下载](https://img.shields.io/github/downloads/NetchX/Netch/total.svg)](https://github.com/NetchX/Netch/releases)
[![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)](https://github.com/NetchX/Netch/actions)
[![网站](https://img.shields.io/website?url=https%3A%2F%2Fnetch.org)](https://netch.org/)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
游戏加速工具
@@ -15,9 +22,17 @@
- [进阶用法](Advanced_Usage.zh-CN.md)
- [依赖](#依赖)
- [语言支持](#语言支持)
## 简介
Netch 是一款 Windows 平台的开源游戏加速工具Netch 可以实现类似 SocksCap64 那样的进程代理,也可以实现 SSTap 那样的全局 TUN/TAP 代理,和 Shadowsocks-Windows 那样的本地 Socks5HTTP 和系统代理。至于连接至远程服务器的代理协议,目前 Netch 支持以下代理协议ShadowsocksVMessSocks5ShadowsocksR
Netch 是一款 Windows 平台的开源游戏加速工具Netch 可以实现类似 SocksCap64 那样的进程代理,也可以实现 SSTap 那样的全局 TUN/TAP 代理,和 Shadowsocks-Windows 那样的本地 Socks5HTTP 和系统代理
至于连接至远程服务器的代理协议,目前 Netch 支持以下代理协议
- Socks5
- Shadowsocks
- ShadowsocksR
- Trojan
- VMess
- VLess
与此同时 Netch 避免了 SSTap 的 NAT 问题 ,检查 NAT 类型即可知道是否有 NAT 问题。使用 SSTap 加速部分 P2P 联机,对 NAT 类型有要求的游戏时,可能会因为 NAT 类型严格遇到无法加入联机,或者其他影响游戏体验的情况
@@ -29,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*
@@ -60,7 +73,6 @@ Netch 支持多种语言,在启动时会根据系统语言选择自身语言
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [unbound](https://github.com/NLnetLabs/unbound)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)

2
modes

Submodule modes updated: 034c8583ad...90ffd0c66a