Compare commits

..

250 Commits

Author SHA1 Message Date
ChsBuffer
d829e347d3 Bump version to 1.9.0 2021-09-21 10:30:04 +08:00
ChsBuffer
a01761d2e2 Bump version to 1.8.9 2021-09-20 20:35:28 +08:00
ChsBuffer
68d87e2ff2 Remove Resolve Server Hostname setting 2021-09-20 20:34:23 +08:00
ChsBuffer
04d6933319 Rename TcpStatusLabel to HTTPStatusLabel 2021-09-20 19:08:01 +08:00
ChsBuffer
e46eef17d0 Create scripts\download\pcap2socks.ps1 2021-09-20 18:54:49 +08:00
ChsBuffer
d3c3958dab fix a typo 2021-09-20 18:20:59 +08:00
ChsBuffer
5ec8d38fd1 Fix build 2021-09-14 09:47:43 +08:00
ChsBuffer
2a8754ecfb Update build 2021-09-14 09:42:00 +08:00
ChsBuffer
cbc6822bff Refactor Cancel Connectivity Test 2021-09-14 08:49:37 +08:00
ChsBuffer
96bd7473ca Refactor AsyncLock 2021-09-14 08:41:30 +08:00
ChsBuffer
54b2b87dec Update Socks5ServerTestUtils.GetSimpleResult() 2021-09-12 03:18:35 +08:00
ChsBuffer
42baed8b8f Catch HttpConnectAsync's exception 2021-09-12 01:34:12 +08:00
ChsBuffer
f68aae6795 Update Setting.cs
- TUNTAP.UseCustomDNS true->false
- V2rayConfig.XrayCone false->true
- JsonIgnore Redirector.ChildProcessHandle
2021-09-12 01:32:48 +08:00
ChsBuffer
8e2008077d Bump version to 1.8.8 2021-09-11 01:32:41 +08:00
ChsBuffer
5b4f0026ff Feature: framework rollForward Major
this allows you to run .NET application targeting 5.x.x running on .NET 6.x.x runtime, but it's unsupported, May behave unexpectedly.
2021-09-11 01:28:27 +08:00
ChsBuffer
89f9dccb87 Fix virtual adapter mode NAT type test result "Wrong STUN server" 2021-09-11 01:19:01 +08:00
ChsBuffer
3e377f2e9d Feature: Server http connect time Test 2021-09-11 01:12:28 +08:00
ChsBuffer
635212f24d Replace NTTController with NatTypetester(Stun.Net)
Enable NAT Type Test for all mode types
Remove Shadowsocks SS
2021-09-10 23:56:25 +08:00
ChsBuffer
46d60babbc Refactor: Update Netch.Servers naming 2021-08-31 11:48:49 +08:00
ChsBuffer
8f80f9abef Update Nuget Packages 2021-08-29 03:54:19 +08:00
Netch
e268f1838f Update MainForm.cs 2021-08-14 09:18:27 +08:00
ChsBuffer
d99229ad50 Fix Netch.csproj loses ApplicationManifest property 2021-08-06 14:01:50 +08:00
ChsBuffer
df85d5797d Feature: remind will get no support from developers if OS is Windows 10 1809 below or CLR version is different from target framework 2021-08-06 06:59:19 +08:00
ChsBuffer
74856ccd61 Update UnitTest.csproj import common.props 2021-08-06 06:59:19 +08:00
ChsBuffer
0165d080c6 Feature: NFController.CheckCore check Core.bin file 2021-08-06 05:05:18 +08:00
ChsBuffer
97fb20e326 Update MainForm.State.StartDisableItems() 2021-08-06 04:55:16 +08:00
ChsBuffer
4d71e2d12f Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.70 to 2.0.71
Remove System.Drawing.Common nuget package
2021-08-06 04:45:59 +08:00
ChsBuffer
0fa83eac3c fix a typo 2021-08-06 02:13:32 +08:00
ChsBuffer
aa6623b063 Create common.props 2021-08-01 02:51:23 +08:00
ChsBuffer
94335ad900 Remove Properties\Settings.settings 2021-08-01 02:50:19 +08:00
ChsBuffer
baf3b39dd3 Fix Socks5 username and password not being saved to the configuration file 2021-08-01 02:49:00 +08:00
ChsBuffer
c12122f7d0 Refactor: Create ModeFeature Enum 2021-07-23 00:44:16 +08:00
ChsBuffer
3e5a4fc102 Update NatTestLock 2021-07-23 00:44:16 +08:00
ChsBuffer
57dbd0193a Move Netch.Models.State Netch.Models.LogLevel to Netch.Enums Namespace 2021-07-23 00:44:16 +08:00
ChsBuffer
5647a6c7ea Refactor SS,SSR Controller Generate Argument 2021-07-23 00:44:16 +08:00
ChsBuffer
773bad4845 Update ServerHelper.cs
Extract and Refactor DelayTestHelper
2021-07-23 00:44:15 +08:00
ChsBuffer
3e943ec6b8 Fix PcapController assert socks5 server false 2021-07-20 08:13:27 +08:00
ChsBuffer
920b068a1e Update DnsUtils 2021-07-19 08:09:57 +08:00
ChsBuffer
7eac7b0837 Fixup Touch Configuration File 2021-07-16 05:40:21 +08:00
ChsBuffer
e1f3390787 Bump version to 1.8.7 2021-07-16 05:25:36 +08:00
ChsBuffer
a62f694908 Refactors 2021-07-16 05:24:36 +08:00
ChsBuffer
98f3218e28 Fixup Remove unused Control.Invoke 2021-07-16 03:46:57 +08:00
ChsBuffer
9da801dc19 Update Log
Remove unused Control.Invoke
2021-07-16 03:39:16 +08:00
ChsBuffer
ff7ae73156 Update using FileStream 2021-07-16 03:25:35 +08:00
ChsBuffer
6810bcc87f Update UnitTest.csproj dependencies 2021-07-16 02:21:17 +08:00
ChsBuffer
3462a3badf add global.json sdk.allowPrerelease=false 2021-07-16 02:20:10 +08:00
ChsBuffer
87a3581dff Fix Configuration.Save() Close FileStream 2021-07-16 00:29:21 +08:00
ChsBuffer
060c42efbc Import Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD 2021-07-15 22:45:05 +08:00
ChsBuffer
72ae9b7bf3 Make Task Analyzer Happy 2021-07-15 20:15:34 +08:00
ChsBuffer
bf4b637940 Add Microsoft.VisualStudio.Threading 2021-07-15 17:57:43 +08:00
ChsBuffer
f8b1c4acd6 Fix Disable edit server if the server is in a group 2021-07-15 16:06:34 +08:00
ChsBuffer
88f3a4940b Add UnitTest 2021-07-15 15:14:40 +08:00
ChsBuffer
cb8dc2163f Update Solution To Include Additional Files 2021-07-15 14:30:46 +08:00
ChsBuffer
ee206f3df0 Update Log 2021-07-15 14:29:56 +08:00
ChsBuffer
d5e1ef1a56 Migrate to CsWin32 2021-07-15 01:54:52 +08:00
ChsBuffer
aeaef4e125 CI Disable download.ps1 2021-07-15 01:54:29 +08:00
ChsBuffer
352602a7ed Fix Confiugration.Save not touch replace target file 2021-07-15 00:55:39 +08:00
ChsBuffer
20d4682d40 Bump version to 1.8.6 2021-07-14 23:25:31 +08:00
ChsBuffer
6ddffcbca4 Remove TraceEvent Package x86 native lib 2021-07-14 23:25:21 +08:00
ChsBuffer
47faf6be88 Update dependencies 2021-07-14 15:52:29 +08:00
ChsBuffer
71028fd6a9 Disable Edit Server if the server belong with a group 2021-07-14 13:44:25 +08:00
ChsBuffer
a03991ddb9 Update V2rayNSharing Util 2021-07-14 13:35:55 +08:00
ChsBuffer
414a43b719 Refactor NotifyIcon Show Button Click 2021-07-13 19:29:34 +08:00
ChsBuffer
32f8d15f86 Fix PcapController.Stop() UI access exception 2021-07-13 19:11:48 +08:00
ChsBuffer
5eb68359d3 Update WebUtil.cs 2021-07-11 04:39:51 +08:00
ChsBuffer
958c28c695 Refactor Updater
Fix Download Update File block UI
2021-07-11 03:59:40 +08:00
ChsBuffer
320b1f66c9 Refactor V2rayConfigUtils methods signature
Refactor V2rayController, TrojanController Write TempConfig File
2021-07-09 21:09:16 +08:00
ChsBuffer
7015784e4f Refactor: Global.NewDefaultJsonSerializerOptions to Global.NewCustomJsonSerializerOptions() 2021-07-09 19:46:56 +08:00
ChsBuffer
64071721d8 Fix xray invalid tcp type none 2021-07-08 14:40:12 +08:00
ChsBuffer
e3b1ae0621 Feature: Xray ServerName(sni) Support
Refactor Generate Xray config file
2021-07-05 20:29:45 +08:00
ChsBuffer
4836e4c913 Fix tun mode bypass rule ip mode did not bypass the remote server address 2021-07-05 05:51:40 +08:00
ChsBuffer
a70b557e0c Update NetRoute.GetBestRouteTemplate() 2021-07-05 03:18:15 +08:00
ChsBuffer
1b19c12824 Fix the access to disposed control when the pap2socks controller start failed 2021-07-05 01:30:21 +08:00
ChsBuffer
35be8bedd0 Update MainController Async 2021-07-05 01:21:46 +08:00
ChsBuffer
5109134843 Log Third-party drivers when open
Log Server.MaskData when start
Remove application Log to console
2021-07-02 19:04:21 +08:00
ChsBuffer
573b5179bb Fix NFController._rdrConfig possible null reference warning 2021-07-02 19:03:29 +08:00
ChsBuffer
8c03f7c6db Fix ServerController return socks5 hostname 2021-06-30 13:31:13 +08:00
ChsBuffer
7d7c91bc68 Merge pull request #680 from xepher/master
Add gRPC support
2021-06-30 13:29:43 +08:00
Shaojun Yang
5ed3f8e073 Fix review issue 2021-06-30 11:12:39 +08:00
Shaojun Yang
7636b0ed27 Add gRPC support 2021-06-29 18:01:11 +08:00
ChsBuffer
29b003bacd Refactor naming 2021-06-28 02:22:51 +08:00
ChsBuffer
c0452552ec Reafctor IController 2021-06-26 23:06:24 +08:00
ChsBuffer
3aee365b48 format Netch.csproj 2021-06-26 16:48:00 +08:00
ChsBuffer
58c5f9d086 Update Async 2021-06-26 16:47:46 +08:00
ChsBuffer
62dc9166ce Refactor Guard.cs 2021-06-26 06:14:08 +08:00
ChsBuffer
e7d04e36ac Update Package Condition 2021-06-26 05:35:52 +08:00
ChsBuffer
8357878b68 Revert "Add DI"
This reverts commit 6f87280d57.
2021-06-13 16:35:54 +08:00
ChsBuffer
f5da527775 Revert "Update namespace"
This reverts commit 9f7fd9020f.
2021-06-13 16:35:38 +08:00
ChsBuffer
9f7fd9020f Update namespace
Cleanup
2021-06-09 15:27:20 +08:00
ChsBuffer
6f87280d57 Add DI 2021-06-09 14:47:42 +08:00
ChsBuffer
76f7c987ac Update SettingForm 2021-06-09 13:54:13 +08:00
ChsBuffer
ff985b14a8 Fix mode not removed in real time 2021-06-09 13:41:31 +08:00
ChsBuffer
951cee1c06 Update TUNController _serverAddress
Update ModeHelper FilesystemWatcher OnNext
2021-06-08 17:12:56 +08:00
Connection Refused
d31617b65c Merge pull request #661 from netchx/dependabot/nuget/Vanara.PInvoke.IpHlpApi-3.3.10
Bump Vanara.PInvoke.IpHlpApi from 3.3.9 to 3.3.10
2021-06-07 08:40:38 +08:00
Connection Refused
80be24120b Merge pull request #660 from netchx/dependabot/nuget/Vanara.PInvoke.User32-3.3.10
Bump Vanara.PInvoke.User32 from 3.3.9 to 3.3.10
2021-06-07 08:40:30 +08:00
dependabot[bot]
4676de32b9 Bump Vanara.PInvoke.IpHlpApi from 3.3.9 to 3.3.10
Bumps [Vanara.PInvoke.IpHlpApi](https://github.com/dahall/vanara) from 3.3.9 to 3.3.10.
- [Release notes](https://github.com/dahall/vanara/releases)
- [Commits](https://github.com/dahall/vanara/commits/v3.3.10)

---
updated-dependencies:
- dependency-name: Vanara.PInvoke.IpHlpApi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-06 16:22:22 +00:00
dependabot[bot]
1775b35513 Bump Vanara.PInvoke.User32 from 3.3.9 to 3.3.10
Bumps [Vanara.PInvoke.User32](https://github.com/dahall/vanara) from 3.3.9 to 3.3.10.
- [Release notes](https://github.com/dahall/vanara/releases)
- [Commits](https://github.com/dahall/vanara/commits/v3.3.10)

---
updated-dependencies:
- dependency-name: Vanara.PInvoke.User32
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-06 16:22:19 +00:00
ChsBuffer
80a92a401c Refactor Mode Directory FileSystemWatcher with Rx 2021-06-06 23:58:31 +08:00
ChsBuffer
b53ea1f7e4 Update Mode.cs 2021-06-06 23:51:57 +08:00
ChsBuffer
486fa195e7 Revert Binding Server,Mode 2021-06-06 23:37:58 +08:00
ChsBuffer
2d000f5f4f Update V2rayConfigUtils.cs TrojanController.cs: sni 2021-06-06 17:38:57 +08:00
ChsBuffer
8a48e321b5 Update Updater, Configuration
Update MainForm Binding Servers,Modes
2021-06-05 18:37:12 +08:00
ChsBuffer
34acb6b281 Fix: UrlDecode Parse Trojan URL password 2021-06-03 12:42:29 +08:00
ChsBuffer
5bbef8db12 Refactor clean temp file
Refactor Mode.GetRules() yield
2021-06-02 14:01:15 +08:00
ChsBuffer
4fba66fab8 Update Interop start failed Message 2021-06-02 11:51:59 +08:00
ChsBuffer
6827207434 FIx: Make SingleInstance start listening after MainForm is Loaded 2021-06-02 11:44:08 +08:00
ChsBuffer
d8e60aa355 Update V2rayConfigUtils 2021-06-01 18:40:13 +08:00
ChsBuffer
f3a7b7cf57 Update InitConsole 2021-06-01 16:42:18 +08:00
ChsBuffer
26fe7ad593 Update V2rayConfigUtils 2021-06-01 16:34:55 +08:00
ChsBuffer
7493f07da9 Migrate to Serilog 2021-05-29 19:54:44 +08:00
ChsBuffer
f6dfb25e3f Show Console NoActive
Implement ConsoleLogger.ShowLog()
2021-05-29 16:41:33 +08:00
Connection Refused
1e5d357f34 Update release.yml 2021-05-29 00:07:00 +08:00
ChsBuffer
63f51a481c Bump version to 1.8.5 2021-05-28 23:39:55 +08:00
Connection Refused
e89c742f3f Add aiodns 2021-05-28 23:31:54 +08:00
ChsBuffer
458c6047af Update cloak.ps1 2021-05-28 23:29:13 +08:00
ChsBuffer
561def7fe1 Fix a typo caused China DNS not be bypassed
close #649
2021-05-28 23:28:34 +08:00
ChsBuffer
9e68fb12fb Update DNSUtils.Lookup() timeout 2021-05-28 23:24:47 +08:00
Connection Refused
d7360b3688 Update dependabot.yml 2021-05-28 23:14:11 +08:00
Connection Refused
7844c183e7 Update download.ps1 2021-05-28 23:10:56 +08:00
Connection Refused
8325bd1fe3 Update README.md 2021-05-28 23:06:35 +08:00
ChsBuffer
0a59d6aa3f Update Text
Update zh-CN
2021-05-28 22:20:19 +08:00
ChsBuffer
7fa05e7dad Update i18N
Update SettingForm AioDNSListenPortTextBox
2021-05-28 21:20:24 +08:00
ChsBuffer
b948040f9d Refactor: Replace -console argument with Show/Hide Console MenuItem 2021-05-28 21:09:23 +08:00
ChsBuffer
0c76198bd4 Update AioDNS default listen port 2021-05-28 20:59:34 +08:00
ChsBuffer
d917e5a8fa Remove AioDNS.RulePath setting
Add AioDNS.ListenPort setting
Update General setting layout
2021-05-28 20:59:15 +08:00
ChsBuffer
015e4ada94 Fix: Disable Task StopIfGoingOnBatteries
close #651
2021-05-28 15:57:15 +08:00
ChsBuffer
86b1741dd0 Revert NatTest Monitor lock 2021-05-28 14:53:27 +08:00
ChsBuffer
4af18025a7 Refactor Interops Debug log 2021-05-27 22:34:30 +08:00
ChsBuffer
3678c98fec Fix AioDNS rule config 2021-05-27 22:34:29 +08:00
ChsBuffer
9f809b4d27 Refactor: Move Updater namespace to Netch.Services 2021-05-27 22:34:29 +08:00
ChsBuffer
e3a3396d18 Refactor Started Ping 2021-05-27 22:34:28 +08:00
Connection Refused
43c19c6698 Update README.md 2021-05-25 12:35:51 +08:00
Connection Refused
9ee2a2a31a Merge pull request #650 from NetchX/dependabot/nuget/Microsoft.Diagnostics.Tracing.TraceEvent-2.0.69
Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.68 to 2.0.69
2021-05-25 12:28:04 +08:00
dependabot[bot]
489c3fc39d Bump Microsoft.Diagnostics.Tracing.TraceEvent from 2.0.68 to 2.0.69
Bumps [Microsoft.Diagnostics.Tracing.TraceEvent](https://github.com/Microsoft/perfview) from 2.0.68 to 2.0.69.
- [Release notes](https://github.com/Microsoft/perfview/releases)
- [Commits](https://github.com/Microsoft/perfview/compare/P2.0.68...P2.0.69)

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-07 23:04:15 +00:00
Connection Refused
b501ed38c4 Enable SelfContained 2021-04-05 02:16:48 +08:00
Connection Refused
6f1b0ee21f Merge remote-tracking branch 'refs/remotes/origin/master' 2021-04-05 02:11:19 +08:00
Connection Refused
ce6d96a779 Bump version to 1.8.3-Beta1145141919 2021-04-05 02:11:08 +08:00
Connection Refused
39f0f87b3a Update Netch.csproj 2021-04-05 02:09:39 +08:00
Connection Refused
642c4d1af8 Fix download.ps1 2021-04-05 02:04:50 +08:00
Connection Refused
d42aa8f184 Update build.ps1 2021-04-05 02:03:02 +08:00
Connection Refused
9c02ef353f Revert 2021-04-05 01:49:13 +08:00
ChsBuffer
1b4e7d41cc Update Netch.csproj: PostBuild 2021-04-04 21:59:43 +08:00
ChsBuffer
3d7dcbbffe Fix open links in about error 2021-04-04 21:59:41 +08:00
ChsBuffer
be9d7d6845 Update build script: exit when curl failed 2021-04-04 21:57:31 +08:00
ChsBuffer
a3620ed162 Normalize all the line endings 2021-04-02 13:58:45 +08:00
ChsBuffer
ba8c60675e Update download.ps1 2021-04-02 13:27:17 +08:00
ChsBuffer
c9a1265231 Update download.ps1 2021-04-02 13:06:21 +08:00
Connection Refused
92b030ebd9 Update release.yml 2021-04-02 08:53:30 +08:00
Connection Refused
7fd24d46d3 Update build.yml 2021-04-02 08:53:17 +08:00
Connection Refused
e2f6a58fde Update download.ps1 2021-04-02 08:50:22 +08:00
ChsBuffer
5f31109bcf Update SuffixVersion 2021-04-02 03:59:49 +08:00
Connection Refused
354608a72c Update README.md 2021-04-02 02:59:29 +08:00
Connection Refused
5803b94ae9 Update NativeMethods 2021-04-02 02:40:13 +08:00
Connection Refused
ee7c6aa608 Update .gitignore 2021-04-02 02:33:46 +08:00
Connection Refused
1099b2c6e6 Bump version to 1.8.3-Beta114514 2021-04-02 02:20:36 +08:00
Connection Refused
295c5958fd Update release.yml 2021-04-02 02:14:34 +08:00
Connection Refused
9a3a85078e Update release.yml 2021-04-02 02:13:03 +08:00
Connection Refused
c14fa70a08 Update download.ps1 2021-04-02 02:04:23 +08:00
Connection Refused
ebcde8cf55 Update build.ps1 2021-04-02 02:00:28 +08:00
Connection Refused
5fca9c55fe Update build.yml 2021-04-02 01:59:23 +08:00
Connection Refused
9f105425ab Update 2021-04-02 01:59:19 +08:00
Connection Refused
4a3d6c49d0 Add files via upload 2021-04-02 01:51:59 +08:00
Connection Refused
fa23561827 Update build.yml 2021-04-02 01:49:24 +08:00
Connection Refused
96b8c42918 Update build.yml 2021-04-02 01:44:27 +08:00
Connection Refused
9b41ea99e5 Update build.yml 2021-04-02 01:43:19 +08:00
Connection Refused
6099891280 Update build.yml 2021-04-02 01:38:33 +08:00
Connection Refused
b8676df2ab Update build.yml 2021-04-02 01:36:17 +08:00
Connection Refused
5970e30974 m 2021-04-02 01:34:56 +08:00
ChsBuffer
37455bb89e Update nfapinet interop 2021-04-02 00:19:57 +08:00
ChsBuffer
9437ec7e5d Update CI(Pull Binaries LFS) 2021-04-01 23:49:53 +08:00
ChsBuffer
93faf8a82e Update submodules 2021-04-01 23:49:25 +08:00
Connection Refused
8a5c0dcd1d Update ci.yml 2021-04-01 23:13:27 +08:00
Connection Refused
559f1dc8a9 Update Redirector 2021-04-01 21:30:32 +08:00
Bruce Wayne
d0c71698aa Update issue forms 2021-04-01 20:24:58 +08:00
Bruce Wayne
98bf6c3c9b Update feature_request.yml 2021-04-01 20:19:37 +08:00
Bruce Wayne
8a6970cc26 Update bug_report.yml 2021-04-01 20:00:39 +08:00
Bruce Wayne
c0b1ae193b Update bug_report.zh-CN.yml 2021-04-01 19:41:45 +08:00
Bruce Wayne
f7d8af6592 New issue forms 2021-04-01 19:35:33 +08:00
Connection Refused
7d7643ad77 Update submodules 2021-04-01 04:36:00 +08:00
Connection Refused
15f9c6d4f5 Update README.zh-CN.md 2021-04-01 04:17:51 +08:00
Connection Refused
732066ccf8 Update README.md 2021-04-01 04:17:37 +08:00
ChsBuffer
483dccc5d2 trim 2021-03-31 19:56:28 +08:00
ChsBuffer
42b609b597 Refactor OpenLogFile 2021-03-31 19:56:23 +08:00
ChsBuffer
7ab89b67c5 Update BUILD.ps1 2021-03-31 18:45:21 +08:00
ChsBuffer
a33c2c3757 Fix Utils.SHA256CheckSum file handle not closed 2021-03-31 17:29:26 +08:00
AmazingDM
268bdb7730 Update UpdateChecker.cs 2021-03-30 14:14:19 +08:00
Connection Refused
ed459ec8d6 Update submodules 2021-03-29 23:39:23 +08:00
Connection Refused
ddd1ca5fac Update NFController 2021-03-29 23:34:20 +08:00
Connection Refused
7c54c1f570 Update Redirector 2021-03-29 23:32:12 +08:00
AmazingDM
ed56d51c4d Update binaries(ICMP hijack) 2021-03-28 22:11:54 +08:00
ChsBuffer
c669097aa5 Update csproj 2021-03-28 16:26:11 +08:00
ChsBuffer
5d74321771 Update MarkFilesOld 2021-03-28 03:52:25 +08:00
ChsBuffer
093fe6404b Updater Skip mark logging directory 2021-03-28 03:49:51 +08:00
ChsBuffer
2760b3c7bd Update TUNController 2021-03-28 03:40:24 +08:00
ChsBuffer
ba17366094 trim 2021-03-28 03:32:21 +08:00
ChsBuffer
6c668684e9 Remove AdapterUtil 2021-03-28 03:29:24 +08:00
ChsBuffer
8d6e4bdd96 Fix Publish Build Missing NTT.exe 2021-03-28 03:15:31 +08:00
186 changed files with 4085 additions and 5631 deletions

View File

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

1
.gitattributes vendored Normal file
View File

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

View File

@@ -1,32 +0,0 @@
---
name: 'Bug report'
about: 'Create a report to help us improve'
title: ''
labels: '需要核实'
assignees: ''
---
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Open Netch
2. ...
**Log**
Attaching any log files in the folder `Netch\logging` is strongly recommended.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS: [e.g. Windows 10 Pro 64-bit 1903]
- Netch Version: [e.g. 1.0.0-STABLE.x64]
**Additional context**
Add any other context about the problem here.

51
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Bug report
description: Create a report to help us improve
labels: bug
body:
- type: textarea
id: error
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: To Reproduce
placeholder: |
1. Open Netch
2. ...
validations:
required: true
- type: checkboxes
id: captcha
attributes:
label: CAPTCHA
description: Please confirm the options below.
options:
- label: Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.
required: true
- type: textarea
id: log
attributes:
label: Log
description: Attaching any log files in the folder `logging` is strongly recommended.
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
render: txt
placeholder: |
- OS: [e.g. Windows 10 x64 Professional Workstation 20H2 19042.928]
- Netch Version: [e.g. 1.0.0]
validations:
required: true
- type: textarea
id: info
attributes:
label: Additional information
description: >
If you have any additional information for us, use the field below.

View File

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

View File

@@ -0,0 +1,43 @@
name: 错误报告
description: 创建错误报告以帮助我们改进
labels: bug
body:
- type: textarea
id: error
attributes:
label: 错误描述
description: 对错误的清晰简洁描述
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: 复现步骤
placeholder: |
1. 打开 Netch 软件
2. ...
validations:
required: true
- type: textarea
id: log
attributes:
label: 日志
description: 强烈建议附上任何在 `logging` 文件夹下面的日志
validations:
required: true
- type: textarea
id: environment
attributes:
label: 操作环境
render: txt
placeholder: |
操作系统:[Windows 10 x64 Professional Workstation 20H2 19042.928]
软件版本:[1.0.0]
validations:
required: true
- type: textarea
id: info
attributes:
label: 额外信息
description: >
下面的文本框中你可以附上跟 issue 相关的截图、文件

View File

@@ -1,8 +1,9 @@
blank_issues_enabled: false
contact_links:
- name: Telegram Channel
url: https://t.me/Netch
url: https://t.me/netch_channel
about: Telegram Channel
- name: Telegram Group
url: https://t.me/Netch_Discuss_Group
about: Telegram Group
url: https://t.me/netch_group
about: Telegram Group

View File

@@ -1,16 +0,0 @@
---
name: 'Feature request'
about: 'Suggest an idea for this project'
title: ''
labels: 'Status: Review Needed'
assignees: ''
---
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
**Describe the feature you want**
A clear and concise description of what you want to happen.
**Additional context** (Optional)
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,11 @@
name: Feature request
description: Suggest an idea for this project
labels: enhancement
body:
- type: textarea
id: description
attributes:
label: Describe the feature you want
description: A clear and concise description of what you want to happen.
validations:
required: true

View File

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

View File

@@ -0,0 +1,11 @@
name: 功能请求
description: 建议这个项目的想法
labels: enhancement
body:
- type: textarea
id: description
attributes:
label: 功能描述
description: 简明扼要地描述需要的功能
validations:
required: true

View File

@@ -1,34 +1,21 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
time: "07:00"
time: "00:00"
timezone: "Asia/Shanghai"
labels:
- "Automatic"
open-pull-requests-limit: 99
- "automatic"
open-pull-requests-limit: 114514
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "daily"
time: "07:15"
time: "00:10"
timezone: "Asia/Shanghai"
labels:
- "Automatic"
open-pull-requests-limit: 99
- package-ecosystem: "gitsubmodule"
directory: "/"
schedule:
interval: "daily"
time: "07:15"
timezone: "Asia/Shanghai"
labels:
- "Automatic"
open-pull-requests-limit: 99
- "automatic"
open-pull-requests-limit: 114514

27
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Netch Build CI
on: [push, pull_request]
jobs:
build:
name: Build
runs-on: windows-latest
steps:
- name: MSBuild
uses: microsoft/setup-msbuild@v1.0.2
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Build
shell: pwsh
run: |
.\build.ps1 -Configuration Release -OutputPath release
- name: Upload
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: actions/upload-artifact@v2
with:
name: Netch
path: release

View File

@@ -1,30 +0,0 @@
name: Netch CI
on:
push:
branches-ignore:
dependabot/**
pull_request:
jobs:
build:
name: Build
runs-on: windows-latest
steps:
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.0.2
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Build Solution
shell: pwsh
run: .\BUILD.ps1
- name: Upload Artifact
continue-on-error: true
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: actions/upload-artifact@v2
with:
name: Netch
path: Netch\bin\x64\Release

View File

@@ -1,46 +1,48 @@
name: Netch Release
name: Netch Release CI
on:
push:
tags:
- '*.*'
- '*.*.*'
jobs:
build:
name: Build
runs-on: windows-latest
steps:
- name: Setup MSBuild
- name: MSBuild
uses: microsoft/setup-msbuild@v1.0.2
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
fetch-depth: 1
- name: Build Solution
shell: pwsh
run: .\PUBLISH.ps1
- name: Package
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
- name: Build
shell: pwsh
run: |
New-Item -ItemType Directory -Path C:\builtfiles -Force > $null
7z a -mx9 C:\builtfiles\Netch.7z .\Netch\bin\Publish\
7z rn C:\builtfiles\Netch.7z Publish 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\Publish\Netch.exe)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
.\build.ps1 -Configuration Release -OutputPath release
- name: Package
shell: pwsh
run: |
7z a -mx9 Netch.7z release
7z rn Netch.7z release Netch
echo "NETCH_SHA256=$(.\sha256.ps1 Netch.7z)" | Out-File -Append -Encoding UTF8 -FilePath $Env:GITHUB_ENV
- name: Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
prerelease: ${{ contains(github.ref, '-') }}
draft: false
files: |
C:\builtfiles\Netch.7z
Netch.7z
body: |
[![](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/Netch) [![](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/Netch_Discuss_Group)
[![](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/netch_channel) [![](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/netch_group)
## Changelogs
* This is an automated deployment of GitHub Actions, the change log should be updated manually soon
## 更新日志
* 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新

10
.gitignore vendored
View File

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

9
.gitmodules vendored
View File

@@ -1,9 +0,0 @@
[submodule "binaries"]
path = binaries
url = https://github.com/NetchX/NetchBinaries
[submodule "modes"]
path = modes
url = https://github.com/NetchX/NetchMode
[submodule "translations"]
path = translations
url = https://github.com/NetchX/NetchTranslation

View File

@@ -1,11 +0,0 @@
Write-Host 'Building'
dotnet build -p:Configuration="Release" `
-p:Platform="x64" `
-p:SolutionDir="$pwd\" `
-restore `
Netch\Netch.csproj
if ($LASTEXITCODE) { exit $LASTEXITCODE }
Write-Host 'Build done'

53
GSF.md
View File

@@ -1,53 +0,0 @@
```json
{
"Type": "",
"Rate": 1,
"Remark": "",
"Hostname": "",
"Port": 0,
"Username": "",
"Password": "",
"EncryptMethod": "",
"Plugin": "",
"PluginOption": "",
"Protocol": "",
"ProtocolParam": "",
"OBFS": "",
"OBFSParam": "",
"UserID": "",
"AlterID": 0,
"TransferProtocol": "",
"FakeType": "",
"Host": "",
"Path": "",
"QUICSecure": "",
"QUICSecret": "",
"TLSSecure": false
}
```
| 字段 | 说明 |
| :- | :- |
| Type | 代理类型HTTP、HTTPS、Socks5、SS、SSR、VMess |
| Rate | 倍率 |
| Remark | 备注 |
| Hostname | 主机名 |
| Port | 端口 |
| Username | 账号HTTP、HTTPS、Socks5 |
| Password | 密码HTTP、HTTPS、Socks5、SS、SSR |
| UserID | 用户 IDVMess |
| AlterID | 额外 IDVMess |
| EncryptMethod | 加密方式SS、SSR、VMess |
| Plugin | 插件SS |
| PluginOption | 插件参数SS |
| Protocol | 协议SSR |
| ProtocolParam | 协议参数SSR |
| OBFS | 混淆SSR |
| OBFSParam | 混淆参数SSR |
| TransferProtcol | 传输协议VMess |
| FakeType | 伪装类型VMess |
| Host | 伪装域名VMess |
| Path | 传输路径VMess |
| QUICSecure | QUIC 加密方式VMess |
| QUICSecret | QUIC 加密密钥VMess |
| TLSSecure | TLS 底层传输安全VMess |

View File

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

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows7</TargetFramework>
<LangVersion>latest</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>none</DebugType>
</PropertyGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +1,41 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "UnitTest\UnitTest.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interop.nfapinet", "Interop.nfapinet\Interop.nfapinet.csproj", "{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.ActiveCfg = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.Build.0 = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.ActiveCfg = Release|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.Build.0 = Release|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|x64
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Debug|x64.ActiveCfg = Debug|Any CPU
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Debug|x64.Build.0 = Debug|Any CPU
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Release|x64.ActiveCfg = Release|Any CPU
{2C968ADF-4822-46A9-A7D9-D05A61CB14DE}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6EC9B043-ACA5-4BB9-96DB-493A2EF6E43F}
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31423.177
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "UnitTest\UnitTest.csproj", "{38240783-9AD2-4A01-84C1-1A3E5F05720F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AdditionalFiles", "AdditionalFiles", "{B7354F81-F79C-4C23-9067-C4DAE91B56F0}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
common.props = common.props
global.json = global.json
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.ActiveCfg = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Debug|x64.Build.0 = Debug|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.ActiveCfg = Release|x64
{4B041B91-5790-4571-8C58-C63FFE4BC9F8}.Release|x64.Build.0 = Release|x64
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Debug|x64.ActiveCfg = Debug|x64
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Debug|x64.Build.0 = Debug|x64
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Release|x64.ActiveCfg = Release|x64
{38240783-9AD2-4A01-84C1-1A3E5F05720F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6EC9B043-ACA5-4BB9-96DB-493A2EF6E43F}
EndGlobalSection
EndGlobal

3
Netch/.gitignore vendored Normal file
View File

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

View File

@@ -2,13 +2,27 @@
{
public static class Constants
{
public const string TempConfig = "data\\last.json";
public const string TempRouteFile = "data\\route.txt";
public const string AioDnsRuleFile = "bin\\aiodns.conf";
public const string NFDriver = "bin\\nfdriver.sys";
public const string NFCore = "bin\\core.bin";
public const string STUNServersFile = "bin\\stun.txt";
public const string LogFile = "logging\\application.log";
public const string OutputTemplate = @"[{Timestamp:yyyy-MM-dd HH:mm:ss}][{Level}] {Message:lj}{NewLine}{Exception}";
public const string EOF = "\r\n";
public const string DefaultGroup = "NONE";
public static class Parameter
{
public const string Show = "-show";
public const string ForceUpdate = "-forceUpdate";
public const string Console = "-console";
}
public const string WintunDllFile = "bin\\wintun.dll";
}
}

View File

@@ -1,32 +1,35 @@
using System;
using System.IO;
using static Netch.Interops.AioDNSInterops;
using System.Threading.Tasks;
using Netch.Interfaces;
using static Netch.Interops.AioDNS;
namespace Netch.Controllers
{
public class DNSController : IController
{
public string Name { get; } = "DNS Service";
public string Name => "DNS Service";
public void Stop()
public async Task StopAsync()
{
Free();
await FreeAsync();
}
/// <summary>
/// 启动DNS服务
/// </summary>
/// <returns></returns>
public void Start()
public async Task StartAsync()
{
Dial(NameList.TYPE_REST, "");
Dial(NameList.TYPE_ADDR, $"{Global.Settings.LocalAddress}:{Global.Settings.AioDNS.ListenPort}");
Dial(NameList.TYPE_LIST, Path.GetFullPath(Global.Settings.AioDNS.RulePath));
Dial(NameList.TYPE_CDNS, $"{Global.Settings.AioDNS.ChinaDNS}");
Dial(NameList.TYPE_ODNS, $"{Global.Settings.AioDNS.OtherDNS}");
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
if (!Init())
throw new Exception("AioDNS start failed");
var aioDnsConfig = Global.Settings.AioDNS;
var listenAddress = Global.Settings.LocalAddress;
Dial(NameList.TYPE_REST, "");
Dial(NameList.TYPE_ADDR, $"{listenAddress}:{aioDnsConfig.ListenPort}");
Dial(NameList.TYPE_LIST, Path.GetFullPath(Constants.AioDnsRuleFile));
Dial(NameList.TYPE_CDNS, $"{aioDnsConfig.ChinaDNS}");
Dial(NameList.TYPE_ODNS, $"{aioDnsConfig.OtherDNS}");
if (!await InitAsync())
throw new Exception("AioDNS start failed.");
}
}
}

View File

@@ -1,90 +1,163 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Netch.Enums;
using Netch.Models;
using Netch.Utils;
using Timer = System.Timers.Timer;
using Serilog;
namespace Netch.Controllers
{
public abstract class Guard
{
private readonly Timer _flushFileStreamTimer = new(300) {AutoReset = true};
private FileStream? _logFileStream;
private StreamWriter? _logStreamWriter;
private bool _redirectToFile = true;
/// <summary>
/// 日志文件(重定向输出文件)
/// </summary>
/// <param name="mainFile">application path relative of Netch\bin</param>
/// <param name="redirectOutput"></param>
/// <param name="encoding">application output encode</param>
protected Guard(string mainFile, bool redirectOutput = true, Encoding? encoding = null)
{
RedirectOutput = redirectOutput;
var fileName = Path.GetFullPath($"bin\\{mainFile}");
if (!File.Exists(fileName))
throw new MessageException(i18N.Translate($"bin\\{mainFile} file not found!"));
Instance = new Process
{
StartInfo =
{
FileName = fileName,
WorkingDirectory = $"{Global.NetchDir}\\bin",
CreateNoWindow = true,
UseShellExecute = !RedirectOutput,
RedirectStandardOutput = RedirectOutput,
StandardOutputEncoding = RedirectOutput ? encoding : null,
RedirectStandardError = RedirectOutput,
StandardErrorEncoding = RedirectOutput ? encoding : null,
WindowStyle = ProcessWindowStyle.Hidden
}
};
}
protected string LogPath => Path.Combine(Global.NetchDir, $"logging\\{Name}.log");
/// <summary>
/// 成功启动关键词
/// </summary>
protected virtual IEnumerable<string> StartedKeywords { get; set; } = new List<string>();
protected virtual IEnumerable<string> StartedKeywords { get; } = new List<string>();
/// <summary>
/// 启动失败关键词
/// </summary>
protected virtual IEnumerable<string> StoppedKeywords { get; set; } = new List<string>();
protected virtual IEnumerable<string> FailedKeywords { get; } = new List<string>();
public abstract string Name { get; }
/// <summary>
/// 主程序名
/// </summary>
public abstract string MainFile { get; protected set; }
private State State { get; set; } = State.Waiting;
protected State State { get; set; } = State.Waiting;
private bool RedirectOutput { get; }
/// <summary>
/// 进程是否可以重定向输出
/// </summary>
protected bool RedirectStd { get; set; } = true;
public Process Instance { get; }
protected bool RedirectToFile
~Guard()
{
get => RedirectStd && _redirectToFile;
set => _redirectToFile = value;
_logFileStream?.Dispose();
_logStreamWriter?.Dispose();
Instance.Dispose();
}
/// <summary>
/// 进程实例
/// </summary>
public Process? Instance { get; private set; }
/// <summary>
/// 程序输出的编码,
/// </summary>
protected virtual Encoding? InstanceOutputEncoding { get; } = null;
public abstract void Stop();
/// <summary>
/// 停止进程
/// </summary>
protected void StopInstance()
protected async Task StartGuardAsync(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
{
State = State.Starting;
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read);
_logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true };
Instance.StartInfo.Arguments = argument;
Instance.Start();
if (priority != ProcessPriorityClass.Normal)
Instance.PriorityClass = priority;
if (RedirectOutput)
{
Task.Run(() => ReadOutput(Instance.StandardOutput)).Forget();
Task.Run(() => ReadOutput(Instance.StandardError)).Forget();
if (!StartedKeywords.Any())
{
// Skip, No started keyword
State = State.Started;
return;
}
// wait ReadOutput change State
for (var i = 0; i < 1000; i++)
{
await Task.Delay(50);
switch (State)
{
case State.Started:
OnStarted();
return;
case State.Stopped:
await StopGuardAsync();
OnStartFailed();
throw new MessageException($"{Name} 控制器启动失败");
}
}
await StopGuardAsync();
throw new MessageException($"{Name} 控制器启动超时");
}
}
private void ReadOutput(TextReader reader)
{
string? line;
while ((line = reader.ReadLine()) != null)
{
_logStreamWriter!.WriteLine(line);
OnReadNewLine(line);
if (State == State.Starting)
{
if (StartedKeywords.Any(s => line.Contains(s)))
State = State.Started;
else if (FailedKeywords.Any(s => line.Contains(s)))
{
OnStartFailed();
State = State.Stopped;
}
}
}
State = State.Stopped;
}
public virtual async Task StopAsync()
{
await StopGuardAsync();
}
protected async Task StopGuardAsync()
{
_logStreamWriter?.Close();
_logFileStream?.Close();
try
{
if (Instance == null || Instance.HasExited)
return;
Instance.Kill();
Instance.WaitForExit();
if (Instance is { HasExited: false })
{
Instance.Kill();
await Instance.WaitForExitAsync();
}
}
catch (Win32Exception e)
{
Logging.Error($"停止 {MainFile} 错误:\n" + e);
Log.Error(e, "停止 {Name} 异常", Instance.ProcessName);
}
catch
{
@@ -92,184 +165,17 @@ namespace Netch.Controllers
}
}
/// <summary>
/// 仅初始化 <see cref="Instance" />,不设定事件处理方法
/// </summary>
/// <param name="argument"></param>
protected virtual void InitInstance(string argument)
protected virtual void OnStarted()
{
Instance = new Process
{
StartInfo =
{
FileName = Path.GetFullPath($"bin\\{MainFile}"),
WorkingDirectory = $"{Global.NetchDir}\\bin",
Arguments = argument,
CreateNoWindow = true,
UseShellExecute = !RedirectStd,
RedirectStandardOutput = RedirectStd,
StandardOutputEncoding = RedirectStd ? InstanceOutputEncoding : null,
RedirectStandardError = RedirectStd,
StandardErrorEncoding = RedirectStd ? InstanceOutputEncoding : null,
WindowStyle = ProcessWindowStyle.Hidden
}
};
if (!File.Exists(Instance.StartInfo.FileName))
throw new MessageException(i18N.Translate($"bin\\{MainFile} file not found!"));
}
/// <summary>
/// 默认行为启动主程序
/// </summary>
/// <param name="argument">主程序启动参数</param>
/// <param name="priority">进程优先级</param>
/// <returns>是否成功启动</returns>
protected void StartInstanceAuto(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
{
State = State.Starting;
// 初始化程序
InitInstance(argument);
if (RedirectToFile)
OpenLogFile();
// 启动程序
Instance!.Start();
if (priority != ProcessPriorityClass.Normal)
Instance.PriorityClass = priority;
if (RedirectStd)
{
Task.Run(() => ReadOutput(Instance.StandardOutput));
Task.Run(() => ReadOutput(Instance.StandardError));
if (!StartedKeywords.Any())
{
State = State.Started;
return;
}
}
else
{
return;
}
// 等待启动
for (var i = 0; i < 1000; i++)
{
Thread.Sleep(10);
switch (State)
{
case State.Started:
Task.Run(OnKeywordStarted);
return;
case State.Stopped:
Stop();
CloseLogFile();
OnKeywordStopped();
throw new MessageException($"{Name} 控制器启动失败");
}
}
Stop();
OnKeywordTimeout();
throw new MessageException($"{Name} 控制器启动超时");
}
#region FileStream
private void OpenLogFile()
{
if (!RedirectToFile)
return;
_logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
_logStreamWriter = new StreamWriter(_logFileStream);
_flushFileStreamTimer.Elapsed += FlushFileStreamTimerEvent;
_flushFileStreamTimer.Enabled = true;
}
private void WriteLog(string line)
{
if (!RedirectToFile)
return;
_logStreamWriter!.WriteLine(line);
}
private void CloseLogFile()
{
if (!RedirectToFile)
return;
_flushFileStreamTimer.Enabled = false;
_logStreamWriter?.Close();
_logFileStream?.Close();
_logStreamWriter = _logStreamWriter = null;
}
#endregion
#region virtual
protected virtual void OnReadNewLine(string line)
{
}
protected virtual void OnKeywordStarted()
{
}
protected virtual void OnKeywordStopped()
protected virtual void OnStartFailed()
{
Utils.Utils.Open(LogPath);
}
protected virtual void OnKeywordTimeout()
{
}
#endregion
protected void ReadOutput(TextReader reader)
{
string? line;
while ((line = reader.ReadLine()) != null)
{
WriteLog(line);
OnReadNewLine(line);
// State == State.Started if !StartedKeywords.Any()
if (State == State.Starting)
{
if (StartedKeywords.Any(s => line.Contains(s)))
State = State.Started;
else if (StoppedKeywords.Any(s => line.Contains(s)))
State = State.Stopped;
}
}
CloseLogFile();
State = State.Stopped;
}
/// <summary>
/// 计时器存储日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FlushFileStreamTimerEvent(object sender, EventArgs e)
{
try
{
_logStreamWriter!.Flush();
}
catch (Exception exception)
{
Logging.Warning($"写入 {Name} 日志错误:\n" + exception.Message);
}
}
}
}

View File

@@ -1,15 +0,0 @@
namespace Netch.Controllers
{
public interface IController
{
/// <summary>
/// 控制器名
/// </summary>
public string Name { get; }
/// <summary>
/// 停止
/// </summary>
public void Stop();
}
}

View File

@@ -1,14 +0,0 @@
using Netch.Models;
namespace Netch.Controllers
{
public interface IModeController : IController
{
/// <summary>
/// 启动
/// </summary>
/// <param name="mode">模式</param>
/// <returns>是否成功</returns>
public abstract void Start(in Mode mode);
}
}

View File

@@ -1,85 +1,94 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Netch.Enums;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Servers;
using Netch.Utils;
using Serilog;
using Serilog.Events;
namespace Netch.Controllers
{
public static class MainController
{
public static Mode? Mode;
public static Socks5Server? Socks5Server { get; private set; }
/// TCP or Both Server
public static Server? Server;
public static Server? Server { get; private set; }
private static Server? _udpServer;
public static Mode? Mode { get; private set; }
public static readonly NTTController NTTController = new();
private static IServerController? _serverController;
private static IServerController? _udpServerController;
public static IServerController? ServerController
{
get => _serverController;
private set => _serverController = value;
}
public static IServerController? UdpServerController
{
get => _udpServerController ?? _serverController;
set => _udpServerController = value;
}
public static Server? UdpServer
{
get => _udpServer ?? Server;
set => _udpServer = value;
}
public static IServerController? ServerController { get; private set; }
public static IModeController? ModeController { get; private set; }
/// <summary>
/// 启动
/// </summary>
/// <param name="server">服务器</param>
/// <param name="mode">模式</param>
/// <returns>是否启动成功</returns>
/// <exception cref="MessageException"></exception>
public static ModeFeature ModeFeatures { get; private set; }
private static readonly AsyncSemaphore Lock = new(1);
public static async Task StartAsync(Server server, Mode mode)
{
await Task.Run(() => Start(server, mode));
}
using var _ = await Lock.EnterAsync();
Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.Remark}");
if (await DnsUtils.LookupAsync(server.Hostname) == null)
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
// TODO Disable NAT Type Test setting
// cache STUN Server ip to prevent "Wrong STUN Server"
DnsUtils.LookupAsync(Global.Settings.STUN_Server).Forget();
public static void Start(Server server, Mode mode)
{
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
Server = server;
Mode = mode;
// 刷新DNS缓存
NativeMethods.FlushDNSResolverCache();
await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules));
if (DnsUtils.Lookup(server.Hostname) == null)
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
// 添加Netch到防火墙
Firewall.AddNetchFwRules();
if (Log.IsEnabled(LogEventLevel.Debug))
Task.Run(() =>
{
// TODO log level setting
Log.Debug("Running Processes: \n{Processes}", string.Join("\n", SystemInfo.Processes(false)));
})
.Forget();
try
{
if (!ModeHelper.SkipServerController(server, mode))
(ModeController, ModeFeatures) = ModeHelper.GetModeControllerByType(mode.Type, out var modePort, out var portName);
if (modePort != null)
TryReleaseTcpPort((ushort)modePort, portName);
if (Server is Socks5Server socks5 && (!socks5.Auth() || ModeFeatures.HasFlag(ModeFeature.SupportSocks5Auth)))
{
StartServer(server, mode, out _serverController);
Socks5Server = socks5;
}
else
{
// Start Server Controller to get a local socks5 server
Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}");
ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5");
Socks5Server = await ServerController.StartAsync(server);
StatusPortInfoText.Socks5Port = Socks5Server.Port;
StatusPortInfoText.UpdateShareLan();
}
StartMode(mode);
// Start Mode Controller
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
await ModeController.StartAsync(Socks5Server, mode);
}
catch (Exception e)
{
Stop();
await StopAsync();
switch (e)
{
@@ -89,81 +98,47 @@ namespace Netch.Controllers
case MessageException:
throw;
default:
Logging.Error(e.ToString());
Utils.Utils.Open(Logging.LogFile);
throw new MessageException($"未处理异常\n{e.Message}");
Log.Error(e, "Unhandled Exception When Start MainController");
Utils.Utils.Open(Constants.LogFile);
throw new MessageException($"{i18N.Translate("Unhandled Exception")}\n{e.Message}");
}
}
}
private static void StartServer(Server server, Mode mode, out IServerController controller)
{
controller = ServerHelper.GetUtilByTypeName(server.Type).GetController();
TryReleaseTcpPort(controller.Socks5LocalPort(), "Socks5");
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
controller.Start(in server, mode);
if (server is Socks5 socks5)
{
if (socks5.Auth())
StatusPortInfoText.Socks5Port = controller.Socks5LocalPort();
}
else
{
StatusPortInfoText.Socks5Port = controller.Socks5LocalPort();
}
}
private static void StartMode(Mode mode)
{
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName);
if (port != null)
TryReleaseTcpPort((ushort) port, portName);
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
ModeController.Start(mode);
}
public static async Task StopAsync()
{
await Task.Run(Stop);
}
if (Lock.CurrentCount == 0)
{
(await Lock.EnterAsync()).Dispose();
return;
}
/// <summary>
/// 停止
/// </summary>
public static void Stop()
{
if (_serverController == null && ModeController == null)
using var _ = await Lock.EnterAsync();
if (ServerController == null && ModeController == null)
return;
Log.Information("Stop Main Controller");
StatusPortInfoText.Reset();
_ = Task.Run(() => NTTController.Stop());
var tasks = new[]
{
Task.Run(() => ServerController?.Stop()),
Task.Run(() => ModeController?.Stop())
Task.Run(() => ServerController?.StopAsync()),
Task.Run(() => ModeController?.StopAsync())
};
try
{
Task.WaitAll(tasks);
await Task.WhenAll(tasks);
}
catch (Exception e)
{
Logging.Error(e.ToString());
Utils.Utils.Open(Logging.LogFile);
Log.Error(e, "MainController Stop Error");
}
ModeController = null;
ServerController = null;
ModeController = null;
ModeFeatures = 0;
}
public static void PortCheck(ushort port, string portName, PortType portType = PortType.Both)
@@ -186,16 +161,9 @@ namespace Netch.Controllers
{
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
{
string fileName;
try
{
fileName = p.MainModule?.FileName ?? throw new Exception(); // TODO what's this exception?
}
catch (Exception e)
{
Logging.Warning(e.ToString());
var fileName = p.MainModule?.FileName;
if (fileName == null)
continue;
}
if (fileName.StartsWith(Global.NetchDir))
{
@@ -210,5 +178,30 @@ namespace Netch.Controllers
PortCheck(port, portName, PortType.TCP);
}
public static async Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
{
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
}
public static async Task<int?> HttpConnectAsync(CancellationToken ctx = default)
{
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
try
{
return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
}
catch (OperationCanceledException)
{
// ignored
}
catch (Exception e)
{
Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception");
}
return null;
}
}
}

View File

@@ -1,53 +1,64 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Threading.Tasks;
using Netch.Interfaces;
using Netch.Interops;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
using Netch.Servers;
using Netch.Utils;
using nfapinet;
using static Netch.Interops.RedirectorInterop;
using Serilog;
using static Netch.Interops.Redirector;
namespace Netch.Controllers
{
public class NFController : IModeController
{
private Server? _server;
private Mode? _mode;
private RedirectorConfig _rdrConfig = null!;
private static readonly ServiceController NFService = new("netfilter2");
private const string BinDriver = "bin\\nfdriver.sys";
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
public string Name { get; } = "Redirector";
public string Name => "Redirector";
public void Start(in Mode mode)
public async Task StartAsync(Socks5Server server, Mode mode)
{
_server = server;
_mode = mode;
_rdrConfig = Global.Settings.Redirector;
CheckDriver();
CheckCore();
Dial(NameList.TYPE_FILTLOP, "false");
Dial(NameList.TYPE_FILTERLOOPBACK, "false");
Dial(NameList.TYPE_FILTERICMP, "true");
var p = PortHelper.GetAvailablePort();
Dial(NameList.TYPE_TCPLISN, p.ToString());
Dial(NameList.TYPE_UDPLISN, p.ToString());
// Server
Dial(NameList.TYPE_FILTUDP, (Global.Settings.Redirector.ProxyProtocol != PortType.TCP).ToString().ToLower());
Dial(NameList.TYPE_FILTTCP, (Global.Settings.Redirector.ProxyProtocol != PortType.UDP).ToString().ToLower());
dial_Server(Global.Settings.Redirector.ProxyProtocol);
Dial(NameList.TYPE_FILTERUDP, _rdrConfig.FilterProtocol.HasFlag(PortType.UDP).ToString().ToLower());
Dial(NameList.TYPE_FILTERTCP, _rdrConfig.FilterProtocol.HasFlag(PortType.TCP).ToString().ToLower());
await DialServerAsync(_rdrConfig.FilterProtocol, _server);
// Mode Rule
dial_Name(mode);
dial_Name(_mode);
// Features
Dial(NameList.TYPE_DNSHOST, Global.Settings.Redirector.DNSHijack ? Global.Settings.Redirector.DNSHijackHost : "");
Dial(NameList.TYPE_DNSHOST, _rdrConfig.DNSHijack ? _rdrConfig.DNSHijackHost : "");
if (!Init())
throw new MessageException("Redirector Start failed, run Netch with \"-console\" argument");
if (!await InitAsync())
throw new MessageException("Redirector start failed.");
}
public void Stop()
public async Task StopAsync()
{
Free();
await FreeAsync();
}
#region CheckRule
@@ -92,54 +103,28 @@ namespace Netch.Controllers
#endregion
private void dial_Server(in PortType portType)
private async Task DialServerAsync(PortType portType, Server server)
{
if (portType == PortType.Both)
{
dial_Server(PortType.TCP);
dial_Server(PortType.UDP);
await DialServerAsync(PortType.TCP, server);
await DialServerAsync(PortType.UDP, server);
return;
}
int offset;
Server server;
IServerController controller;
var offset = portType == PortType.UDP ? UdpNameListOffset : 0;
if (portType == PortType.UDP)
{
offset = UdpNameListOffset;
server = MainController.UdpServer!;
controller = MainController.UdpServerController!;
}
else
{
offset = 0;
server = MainController.Server!;
controller = MainController.ServerController!;
}
if (server is Socks5 socks5)
if (server is Socks5Server socks5)
{
Dial(NameList.TYPE_TCPTYPE + offset, "Socks5");
Dial(NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
Dial(NameList.TYPE_TCPHOST + offset, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
Dial(NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
Dial(NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
Dial(NameList.TYPE_TCPMETH + offset, string.Empty);
}
else if (server is Shadowsocks shadowsocks && !shadowsocks.HasPlugin() && Global.Settings.Redirector.RedirectorSS)
{
Dial(NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
Dial(NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
Dial(NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod);
Dial(NameList.TYPE_TCPPASS + offset, shadowsocks.Password);
}
else
{
Dial(NameList.TYPE_TCPTYPE + offset, "Socks5");
Dial(NameList.TYPE_TCPHOST + offset, $"127.0.0.1:{controller.Socks5LocalPort()}");
Dial(NameList.TYPE_TCPUSER + offset, string.Empty);
Dial(NameList.TYPE_TCPPASS + offset, string.Empty);
Dial(NameList.TYPE_TCPMETH + offset, string.Empty);
Trace.Assert(false);
}
}
@@ -147,7 +132,7 @@ namespace Netch.Controllers
{
Dial(NameList.TYPE_CLRNAME, "");
var invalidList = new List<string>();
foreach (var s in mode.FullRule)
foreach (var s in mode.GetRules())
{
if (s.StartsWith("!"))
{
@@ -168,15 +153,21 @@ namespace Netch.Controllers
Dial(NameList.TYPE_BYPNAME, "^" + Global.NetchDir.ToRegexString() + @"((?!NTT\.exe).)*$");
}
private void CheckCore()
{
if (!File.Exists(Constants.NFCore))
throw new MessageException(i18N.Translate("\"Core.bin\" is missing. Please check your Antivirus software"));
}
#region DriverUtil
private static void CheckDriver()
{
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
var binFileVersion = Utils.Utils.GetFileVersion(Constants.NFDriver);
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
Logging.Info("内置驱动版本: " + binFileVersion);
Logging.Info("系统驱动版本: " + systemFileVersion);
Log.Information("内置驱动版本: {Name}", binFileVersion);
Log.Information("系统驱动版本: {Name}", systemFileVersion);
if (!File.Exists(SystemDriver))
{
@@ -206,7 +197,7 @@ namespace Netch.Controllers
if (!reinstall)
return;
Logging.Info("更新驱动");
Log.Information("更新驱动");
UninstallDriver();
InstallDriver();
}
@@ -217,18 +208,18 @@ namespace Netch.Controllers
/// <returns>驱动是否安装成功</returns>
private static void InstallDriver()
{
Logging.Info("安装 NF 驱动");
Log.Information("安装 NF 驱动");
if (!File.Exists(BinDriver))
if (!File.Exists(Constants.NFDriver))
throw new MessageException(i18N.Translate("builtin driver files missing, can't install NF driver"));
try
{
File.Copy(BinDriver, SystemDriver);
File.Copy(Constants.NFDriver, SystemDriver);
}
catch (Exception e)
{
Logging.Error("驱动复制失败\n" + e);
Log.Error(e, "驱动复制失败\n");
throw new MessageException($"Copy NF driver file failed\n{e.Message}");
}
@@ -237,11 +228,11 @@ namespace Netch.Controllers
var result = NFAPI.nf_registerDriver("netfilter2");
if (result == NF_STATUS.NF_STATUS_SUCCESS)
{
Logging.Info("驱动安装成功");
Log.Information("驱动安装成功");
}
else
{
Logging.Error($"注册驱动失败,返回值:{result}");
Log.Error("注册驱动失败: {Result}", result);
throw new MessageException($"Register NF driver failed\n{result}");
}
}
@@ -252,7 +243,7 @@ namespace Netch.Controllers
/// <returns>是否成功卸载</returns>
public static bool UninstallDriver()
{
Logging.Info("卸载 NF 驱动");
Log.Information("卸载 NF 驱动");
try
{
if (NFService.Status == ServiceControllerStatus.Running)

View File

@@ -1,103 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Netch.Utils;
namespace Netch.Controllers
{
public class NTTController : Guard, IController
{
public override string MainFile { get; protected set; } = "NTT.exe";
public override string Name { get; } = "NTT";
public override void Stop()
{
StopInstance();
}
/// <summary>
/// 启动 NatTypeTester
/// </summary>
/// <returns></returns>
public async Task<(string?, string?, string?)> Start()
{
string? localEnd = null, publicEnd = null, result = null, bindingTest = null;
try
{
InitInstance($" {Global.Settings.STUN_Server} {Global.Settings.STUN_Server_Port}");
Instance!.Start();
var output = await Instance.StandardOutput.ReadToEndAsync();
var error = await Instance.StandardError.ReadToEndAsync();
try
{
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), $"{output}\r\n{error}");
}
catch (Exception e)
{
Logging.Warning($"写入 {Name} 日志错误:\n" + e.Message);
}
if (output.IsNullOrWhiteSpace())
if (!error.IsNullOrWhiteSpace())
{
error = error.Trim();
var errorFirst = error.Substring(0, error.IndexOf('\n')).Trim();
return (errorFirst.SplitTrimEntries(':').Last(), null, null);
}
foreach (var line in output.Split('\n'))
{
var str = line.SplitTrimEntries(':');
if (str.Length < 2)
continue;
var key = str[0];
var value = str[1];
switch (key)
{
case "Other address is":
case "Nat mapping behavior":
case "Nat filtering behavior":
break;
case "Binding test":
bindingTest = value;
break;
case "Local address":
localEnd = value;
break;
case "Mapped address":
publicEnd = value;
break;
case "result":
result = value;
break;
}
}
if (bindingTest == "Fail")
result = "Fail";
return (result, localEnd, publicEnd);
}
catch (Exception e)
{
Logging.Error($"{Name} 控制器出错:\n" + e);
try
{
Stop();
}
catch
{
// ignored
}
return (null, null, null);
}
}
}
}

View File

@@ -1,81 +1,93 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Netch.Forms;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Servers;
using Netch.Utils;
namespace Netch.Controllers
{
public class PcapController : Guard, IModeController
{
public override string Name { get; } = "pcap2socks";
private readonly LogForm _form;
private Mode? _mode;
private Server? _server;
public override string MainFile { get; protected set; } = "pcap2socks.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"└"};
private readonly OutboundAdapter _outbound = new();
protected override Encoding? InstanceOutputEncoding { get; } = Encoding.UTF8;
private LogForm? _form;
public void Start(in Mode mode)
public PcapController() : base("pcap2socks.exe", encoding: Encoding.UTF8)
{
var server = MainController.Server!;
_form = new LogForm(Global.MainForm);
_form.CreateControl();
}
var argument = new StringBuilder($@"-i \Device\NPF_{_outbound.NetworkInterface.Id}");
if (server is Socks5 socks5 && !socks5.Auth())
argument.Append($" --destination {server.AutoResolveHostname()}:{server.Port}");
protected override IEnumerable<string> StartedKeywords { get; } = new[] { "└" };
public override string Name => "pcap2socks";
public async Task StartAsync(Socks5Server server, Mode mode)
{
_server = server;
_mode = mode;
var outboundNetworkInterface = NetworkInterfaceUtils.GetBest();
var argument = new StringBuilder($@"-i \Device\NPF_{outboundNetworkInterface.Id}");
if (_server is Socks5Server socks5 && !socks5.Auth())
argument.Append($" --destination {await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
else
argument.Append($" --destination 127.0.0.1:{Global.Settings.Socks5LocalPort}");
Trace.Assert(false);
argument.Append($" {mode.FullRule.FirstOrDefault() ?? "-P n"}");
StartInstanceAuto(argument.ToString());
argument.Append($" {_mode.GetRules().FirstOrDefault() ?? "-P n"}");
await StartGuardAsync(argument.ToString());
}
public override async Task StopAsync()
{
Global.MainForm.Invoke(new Action(() => { _form.Close(); }));
await StopGuardAsync();
}
~PcapController()
{
_form.Dispose();
}
protected override void OnReadNewLine(string line)
{
Global.MainForm.BeginInvoke(new Action(() =>
{
if (!_form!.IsDisposed)
if (!_form.IsDisposed)
_form.richTextBox1.AppendText(line + "\n");
}));
}
protected override void OnKeywordStarted()
protected override void OnStarted()
{
Global.MainForm.BeginInvoke(new Action(() => { _form!.Show(); }));
Global.MainForm.BeginInvoke(new Action(() => _form.Show()));
}
protected override void OnKeywordStopped()
protected override void OnStartFailed()
{
if (File.ReadAllText(LogPath).Length == 0)
if (new FileInfo(LogPath).Length == 0)
{
Task.Run(() =>
{
Thread.Sleep(1000);
Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies");
});
{
Thread.Sleep(1000);
Utils.Utils.Open("https://github.com/zhxie/pcap2socks#dependencies");
})
.Forget();
throw new MessageException("Pleases install pcap2socks's dependency");
}
Utils.Utils.Open(LogPath);
}
public override void Stop()
{
_form!.Close();
StopInstance();
}
}
}

View File

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

View File

@@ -8,6 +8,7 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Netch.Models.GitHubRelease;
using Netch.Utils;
using Serilog;
namespace Netch.Controllers
{
@@ -19,8 +20,8 @@ namespace Netch.Controllers
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2021";
public const string AssemblyVersion = @"1.8.3";
private const string Suffix = @"Beta5";
public const string AssemblyVersion = @"1.9.0";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
@@ -36,48 +37,43 @@ namespace Netch.Controllers
public static event EventHandler? NewVersionNotFound;
public static async Task Check(bool isPreRelease)
public static async Task CheckAsync(bool isPreRelease)
{
try
{
var updater = new GitHubRelease(Owner, Repo);
var url = updater.AllReleaseUrl;
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
var (_, json) = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
var releases = JsonSerializer.Deserialize<List<Release>>(json)!;
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
Logging.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
LatestRelease = GetLatestRelease(releases, isPreRelease);
Log.Information("Github 最新发布版本: {Version}", LatestRelease.tag_name);
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
{
Logging.Info("发现新版本");
NewVersionFound?.Invoke(null, new EventArgs());
Log.Information("发现新版本");
NewVersionFound?.Invoke(null, EventArgs.Empty);
}
else
{
Logging.Info("目前是最新版本");
NewVersionNotFound?.Invoke(null, new EventArgs());
Log.Information("目前是最新版本");
NewVersionNotFound?.Invoke(null, EventArgs.Empty);
}
}
catch (Exception e)
{
if (e is WebException)
Logging.Warning($"获取新版本失败: {e.Message}");
Log.Warning(e, "获取新版本失败");
else
Logging.Warning(e.ToString());
Log.Error(e, "获取新版本异常");
NewVersionFoundFailed?.Invoke(null, new EventArgs());
NewVersionFoundFailed?.Invoke(null, EventArgs.Empty);
}
}
public static void GetLatestUpdateFileNameAndHash(out string fileName, out string sha256, string? keyword = null)
public static (string fileName, string sha256) GetLatestUpdateFileNameAndHash(string? keyword = null)
{
fileName = string.Empty;
sha256 = string.Empty;
var matches = Regex.Matches(LatestRelease.body, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline)
.Cast<Match>()
.Skip(2);
var matches = Regex.Matches(LatestRelease.body, @"^\| (?<filename>.*) \| (?<sha256>.*) \|\r?$", RegexOptions.Multiline).Skip(2);
/*
Skip(2)
@@ -87,8 +83,7 @@ namespace Netch.Controllers
Match match = keyword == null ? matches.First() : matches.First(m => m.Groups["filename"].Value.Contains(keyword));
fileName = match.Groups["filename"].Value;
sha256 = match.Groups["sha256"].Value;
return (match.Groups["filename"].Value, match.Groups["sha256"].Value);
}
public static string GetLatestReleaseContent()
@@ -104,5 +99,14 @@ namespace Netch.Controllers
return sb.ToString();
}
private static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
{
if (!isPreRelease)
releases = releases.Where(release => !release.prerelease);
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionUtil.VersionComparer());
return ordered.ElementAt(0);
}
}
}
}

View File

@@ -1,10 +1,9 @@
namespace Netch.Models
namespace Netch.Enums
{
public enum LogLevel
{
INFO,
WARNING,
ERROR,
DEBUG
ERROR
}
}

View File

@@ -0,0 +1,13 @@
using System;
namespace Netch.Enums
{
[Flags]
public enum ModeFeature
{
SupportSocks5 = 0,
SupportIPv4 = 0,
SupportSocks5Auth = 0b_0001,
SupportIPv6 = 0b_0100
}
}

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

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

View File

@@ -1,4 +1,4 @@
namespace Netch.Models
namespace Netch.Enums
{
/// <summary>
/// 状态

View File

@@ -7,5 +7,7 @@ namespace Netch
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
public static bool AlwaysShowNewVersionFound { get; set; }
public static bool NoSupport { get; set; }
}
}

View File

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

View File

@@ -1,9 +1,9 @@
using System;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using Netch.Properties;
using Netch.Utils;
namespace Netch.Forms
{
@@ -50,13 +50,13 @@ namespace Netch.Forms
MessageBoxX.Show(i18N.Translate("Please select an IP"));
}
private void ControlButton_Click(object sender, EventArgs e)
private async void ControlButton_Click(object sender, EventArgs e)
{
Global.Settings.TUNTAP.BypassIPs.Clear();
foreach (var ip in IPListBox.Items)
Global.Settings.TUNTAP.BypassIPs.Add((string) ip);
Global.Settings.TUNTAP.BypassIPs.Add((string)ip);
Configuration.Save();
await Configuration.SaveAsync();
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}

View File

@@ -74,7 +74,7 @@ namespace Netch.Forms
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.Text = "LogForm";
this.Load += new System.EventHandler(this.Notifycation_Load);
this.Load += new System.EventHandler(this.LogForm_Load);
this.ResumeLayout(false);
this.PerformLayout();

View File

@@ -1,8 +1,9 @@
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Vanara.PInvoke;
using static Vanara.PInvoke.User32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using static Windows.Win32.PInvoke;
namespace Netch.Forms
{
@@ -34,21 +35,21 @@ namespace Netch.Forms
private void Parent_Activated(object? sender, EventArgs? e)
{
SetWindowPos(Handle,
HWND.HWND_TOPMOST,
SetWindowPos(new HWND(Handle),
new HWND(-1),
0,
0,
0,
0,
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW);
SetWindowPos(Handle,
HWND.HWND_NOTOPMOST,
SetWindowPos(new HWND(Handle),
new HWND(-2),
0,
0,
0,
0,
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_SHOWWINDOW);
SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW);
}
private void richTextBox1_TextChanged(object? sender, EventArgs? e)
@@ -60,7 +61,7 @@ namespace Netch.Forms
richTextBox1.ScrollToCaret();
}
private void Notifycation_Load(object? sender, EventArgs? e)
private void LogForm_Load(object? sender, EventArgs? e)
{
_parent.LocationChanged += Parent_Move;
_parent.SizeChanged += Parent_Move;

View File

@@ -40,6 +40,7 @@
this.UpdateServersFromSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.OptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.OpenDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ShowHideConsoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.CleanDNSCacheToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -72,6 +73,7 @@
this.DownloadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.UploadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.blankToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.HttpStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.NatTypeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.NatTypeStatusLightLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.ControlButton = new System.Windows.Forms.Button();
@@ -190,6 +192,7 @@
//
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.OpenDirectoryToolStripMenuItem,
this.ShowHideConsoleToolStripMenuItem,
this.CleanDNSCacheToolStripMenuItem,
this.UninstallServiceToolStripMenuItem,
this.removeNetchFirewallRulesToolStripMenuItem});
@@ -205,6 +208,13 @@
this.OpenDirectoryToolStripMenuItem.Text = "Open Directory";
this.OpenDirectoryToolStripMenuItem.Click += new System.EventHandler(this.OpenDirectoryToolStripMenuItem_Click);
//
// ShowHideConsoleToolStripMenuItem
//
this.ShowHideConsoleToolStripMenuItem.Name = "ShowHideConsoleToolStripMenuItem";
this.ShowHideConsoleToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.ShowHideConsoleToolStripMenuItem.Text = "Show/Hide Console";
this.ShowHideConsoleToolStripMenuItem.Click += new System.EventHandler(this.ShowHideConsoleToolStripMenuItem_Click);
//
// CleanDNSCacheToolStripMenuItem
//
this.CleanDNSCacheToolStripMenuItem.Name = "CleanDNSCacheToolStripMenuItem";
@@ -512,6 +522,7 @@
this.DownloadSpeedLabel,
this.UploadSpeedLabel,
this.blankToolStripStatusLabel,
this.HttpStatusLabel,
this.NatTypeStatusLabel,
this.NatTypeStatusLightLabel});
this.StatusStrip.Location = new System.Drawing.Point(0, 272);
@@ -551,9 +562,18 @@
// blankToolStripStatusLabel
//
this.blankToolStripStatusLabel.Name = "blankToolStripStatusLabel";
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(494, 17);
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(240, 17);
this.blankToolStripStatusLabel.Spring = true;
//
// HttpStatusLabel
//
this.HttpStatusLabel.Name = "HttpStatusLabel";
this.HttpStatusLabel.Size = new System.Drawing.Size(41, 17);
this.HttpStatusLabel.Text = "HTTP:";
this.HttpStatusLabel.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
this.HttpStatusLabel.Visible = false;
this.HttpStatusLabel.Click += new System.EventHandler(this.TcpStatusLabel_Click);
//
// NatTypeStatusLabel
//
this.NatTypeStatusLabel.Name = "NatTypeStatusLabel";
@@ -743,7 +763,7 @@
private System.Windows.Forms.ToolStripMenuItem ImportServersFromClipboardToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem ManageSubscribeLinksToolStripMenuItem;
private System.Windows.Forms.MenuStrip MenuStrip;
private System.Windows.Forms.ComboBox ModeComboBox;
public System.Windows.Forms.ComboBox ModeComboBox;
private System.Windows.Forms.Label ModeLabel;
private System.Windows.Forms.ToolStripMenuItem ModeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem HelpToolStripMenuItem;
@@ -782,5 +802,7 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem;
private System.Windows.Forms.ToolStripStatusLabel HttpStatusLabel;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -57,4 +57,16 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="MenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="StatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>130, 17</value>
</metadata>
<metadata name="NotifyIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>246, 17</value>
</metadata>
<metadata name="NotifyMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>359, 17</value>
</metadata>
</root>

View File

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

View File

@@ -1,7 +1,7 @@
using System.IO;
using System.Text;
namespace Netch.Forms.Mode
namespace Netch.Forms.ModeForms
{
public static class ModeEditorUtils
{

View File

@@ -1,9 +1,9 @@
using System;
using System.Windows.Forms;
namespace Netch.Forms.Mode
namespace Netch.Forms.ModeForms
{
partial class Process
partial class ProcessForm
{
/// <summary>
/// Required designer variable.
@@ -180,7 +180,7 @@ namespace Netch.Forms.Mode
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.MaximizeBox = false;
this.Name = "Process";
this.Name = "ProcessForm";
this.Padding = new System.Windows.Forms.Padding(12, 5, 12, 5);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Create Process Mode";

View File

@@ -1,30 +1,31 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Dialogs;
using Microsoft.WindowsAPICodePack.Dialogs;
using Netch.Controllers;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Netch.Enums;
namespace Netch.Forms.Mode
namespace Netch.Forms.ModeForms
{
public partial class Process : Form
public partial class ProcessForm : Form
{
/// <summary>
/// 被编辑的模式
/// </summary>
private readonly Models.Mode? _mode;
private readonly Mode? _mode;
/// <summary>
/// 编辑模式
/// </summary>
/// <param name="mode">模式</param>
public Process(Models.Mode? mode = null)
public ProcessForm(Mode? mode = null)
{
if (mode != null && mode.Type is not 0)
if (mode != null && mode.Type is not ModeType.Process)
throw new ArgumentOutOfRangeException();
InitializeComponent();
@@ -62,7 +63,7 @@ namespace Netch.Forms.Mode
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
RemarkTextBox.Text = _mode.Remark;
FilenameTextBox.Text = _mode.RelativePath;
RuleAddRange(_mode.Rule);
RuleAddRange(_mode.Content);
}
i18N.TranslateForm(this);
@@ -116,8 +117,8 @@ namespace Netch.Forms.Mode
if (_mode != null)
{
_mode.Remark = RemarkTextBox.Text;
_mode.Rule.Clear();
_mode.Rule.AddRange(RuleRichTextBox.Lines);
_mode.Content.Clear();
_mode.Content.AddRange(RuleRichTextBox.Lines);
_mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
@@ -132,13 +133,13 @@ namespace Netch.Forms.Mode
return;
}
var mode = new Models.Mode(fullName)
var mode = new Mode(fullName)
{
Type = 0,
Type = ModeType.Process,
Remark = RemarkTextBox.Text
};
mode.Rule.AddRange(RuleRichTextBox.Lines);
mode.Content.AddRange(RuleRichTextBox.Lines);
mode.WriteFile();
MessageBoxX.Show(i18N.Translate("Mode added successfully"));

View File

@@ -1,9 +1,9 @@
using System.ComponentModel;
using Netch.Properties;
namespace Netch.Forms.Mode
namespace Netch.Forms.ModeForms
{
partial class Route
partial class RouteForm
{
/// <summary>
/// Required designer variable.
@@ -166,7 +166,7 @@ namespace Netch.Forms.Mode
this.ClientSize = new System.Drawing.Size(356, 419);
this.Controls.Add(this.ConfigurationGroupBox);
this.Controls.Add(this.ControlButton);
this.Name = "Route";
this.Name = "RouteForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Create Route Table Rule";
this.Load += new System.EventHandler(this.Route_Load);

View File

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

View File

@@ -38,13 +38,13 @@ namespace Netch.Forms
InitializeComponent();
_checkActions.Add(RemarkTextBox, s => true);
_saveActions.Add(RemarkTextBox, s => Server.Remark = (string) s);
_saveActions.Add(RemarkTextBox, s => Server.Remark = (string)s);
_checkActions.Add(AddressTextBox, s => s != string.Empty);
_saveActions.Add(AddressTextBox, s => Server.Hostname = (string) s);
_saveActions.Add(AddressTextBox, s => Server.Hostname = (string)s);
_checkActions.Add(PortTextBox, s => ushort.TryParse(s, out var port) && port != 0);
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string) s));
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string)s));
}
protected abstract string TypeName { get; }
@@ -74,6 +74,8 @@ namespace Netch.Forms
AddSaveButton();
i18N.TranslateForm(this);
ConfigurationGroupBox.Enabled = !Server.IsInGroup();
ConfigurationGroupBox.ResumeLayout(false);
ConfigurationGroupBox.PerformLayout();
ResumeLayout(false);
@@ -99,7 +101,7 @@ namespace Netch.Forms
};
_checkActions.Add(textBox, check);
_saveActions.Add(textBox, o => save.Invoke((string) o));
_saveActions.Add(textBox, o => save.Invoke((string)o));
ConfigurationGroupBox.Controls.AddRange(new Control[]
{
textBox,
@@ -131,7 +133,7 @@ namespace Netch.Forms
comboBox.Items.AddRange(values.ToArray());
comboBox.SelectedIndex = values.IndexOf(value);
comboBox.DrawItem += Utils.Utils.DrawCenterComboBox;
_saveActions.Add(comboBox, o => save.Invoke((string) o));
_saveActions.Add(comboBox, o => save.Invoke((string)o));
ConfigurationGroupBox.Controls.AddRange(new Control[]
{
comboBox,
@@ -159,7 +161,7 @@ namespace Netch.Forms
Text = remark
};
_saveActions.Add(checkBox, o => save.Invoke((bool) o));
_saveActions.Add(checkBox, o => save.Invoke((bool)o));
ConfigurationGroupBox.Controls.AddRange(new Control[]
{
checkBox

View File

@@ -39,7 +39,6 @@ namespace Netch.Forms
this.HTTPPortLabel = new System.Windows.Forms.Label();
this.HTTPPortTextBox = new System.Windows.Forms.TextBox();
this.AllowDevicesCheckBox = new System.Windows.Forms.CheckBox();
this.ResolveServerHostnameCheckBox = new System.Windows.Forms.CheckBox();
this.ServerPingTypeLabel = new System.Windows.Forms.Label();
this.ICMPingRadioBtn = new System.Windows.Forms.RadioButton();
this.TCPingRadioBtn = new System.Windows.Forms.RadioButton();
@@ -54,14 +53,13 @@ namespace Netch.Forms
this.LanguageLabel = new System.Windows.Forms.Label();
this.LanguageComboBox = new System.Windows.Forms.ComboBox();
this.NFTabPage = new System.Windows.Forms.TabPage();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.ProcessProxyProtocolLabel = new System.Windows.Forms.Label();
this.ProcessProxyProtocolComboBox = new System.Windows.Forms.ComboBox();
this.ProcessFilterProtocolLabel = new System.Windows.Forms.Label();
this.ProcessFilterProtocolComboBox = new System.Windows.Forms.ComboBox();
this.DNSHijackCheckBox = new System.Windows.Forms.CheckBox();
this.DNSHijackHostTextBox = new System.Windows.Forms.TextBox();
this.ICMPHijackCheckBox = new System.Windows.Forms.CheckBox();
this.ICMPHijackHostTextBox = new System.Windows.Forms.TextBox();
this.RedirectorSSCheckBox = new System.Windows.Forms.CheckBox();
this.FilterICMPCheckBox = new System.Windows.Forms.CheckBox();
this.ICMPDelayLabel = new System.Windows.Forms.Label();
this.ICMPDelayTextBox = new System.Windows.Forms.TextBox();
this.ChildProcessHandleCheckBox = new System.Windows.Forms.CheckBox();
this.WinTUNTabPage = new System.Windows.Forms.TabPage();
this.WinTUNGroupBox = new System.Windows.Forms.GroupBox();
@@ -99,24 +97,24 @@ namespace Netch.Forms
this.StopWhenExitedCheckBox = new System.Windows.Forms.CheckBox();
this.StartWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
this.MinimizeWhenStartedCheckBox = new System.Windows.Forms.CheckBox();
this.NoSupportDialogCheckBox = new System.Windows.Forms.CheckBox();
this.RunAtStartupCheckBox = new System.Windows.Forms.CheckBox();
this.CheckUpdateWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
this.CheckBetaUpdateCheckBox = new System.Windows.Forms.CheckBox();
this.UpdateServersWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
this.AioDNSTabPage = new System.Windows.Forms.TabPage();
this.AioDNSRuleRuleLabel = new System.Windows.Forms.Label();
this.AioDNSRulePathTextBox = new System.Windows.Forms.TextBox();
this.ChinaDNSLabel = new System.Windows.Forms.Label();
this.ChinaDNSTextBox = new System.Windows.Forms.TextBox();
this.OtherDNSLabel = new System.Windows.Forms.Label();
this.OtherDNSTextBox = new System.Windows.Forms.TextBox();
this.AioDNSListenPortLabel = new System.Windows.Forms.Label();
this.AioDNSListenPortTextBox = new System.Windows.Forms.TextBox();
this.ControlButton = new System.Windows.Forms.Button();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.TabControl.SuspendLayout();
this.GeneralTabPage.SuspendLayout();
this.PortGroupBox.SuspendLayout();
this.NFTabPage.SuspendLayout();
this.groupBox1.SuspendLayout();
this.WinTUNTabPage.SuspendLayout();
this.WinTUNGroupBox.SuspendLayout();
this.v2rayTabPage.SuspendLayout();
@@ -145,7 +143,6 @@ namespace Netch.Forms
//
this.GeneralTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
this.GeneralTabPage.Controls.Add(this.PortGroupBox);
this.GeneralTabPage.Controls.Add(this.ResolveServerHostnameCheckBox);
this.GeneralTabPage.Controls.Add(this.ServerPingTypeLabel);
this.GeneralTabPage.Controls.Add(this.ICMPingRadioBtn);
this.GeneralTabPage.Controls.Add(this.TCPingRadioBtn);
@@ -175,7 +172,7 @@ namespace Netch.Forms
this.PortGroupBox.Controls.Add(this.AllowDevicesCheckBox);
this.PortGroupBox.Location = new System.Drawing.Point(8, 6);
this.PortGroupBox.Name = "PortGroupBox";
this.PortGroupBox.Size = new System.Drawing.Size(241, 140);
this.PortGroupBox.Size = new System.Drawing.Size(241, 115);
this.PortGroupBox.TabIndex = 0;
this.PortGroupBox.TabStop = false;
this.PortGroupBox.Text = "Local Port";
@@ -217,37 +214,27 @@ namespace Netch.Forms
// AllowDevicesCheckBox
//
this.AllowDevicesCheckBox.AutoSize = true;
this.AllowDevicesCheckBox.Location = new System.Drawing.Point(6, 107);
this.AllowDevicesCheckBox.Location = new System.Drawing.Point(6, 84);
this.AllowDevicesCheckBox.Name = "AllowDevicesCheckBox";
this.AllowDevicesCheckBox.Size = new System.Drawing.Size(206, 21);
this.AllowDevicesCheckBox.TabIndex = 6;
this.AllowDevicesCheckBox.TabIndex = 4;
this.AllowDevicesCheckBox.Text = "Allow other Devices to connect";
this.AllowDevicesCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.AllowDevicesCheckBox.UseVisualStyleBackColor = true;
//
// ResolveServerHostnameCheckBox
//
this.ResolveServerHostnameCheckBox.AutoSize = true;
this.ResolveServerHostnameCheckBox.Location = new System.Drawing.Point(267, 15);
this.ResolveServerHostnameCheckBox.Name = "ResolveServerHostnameCheckBox";
this.ResolveServerHostnameCheckBox.Size = new System.Drawing.Size(176, 21);
this.ResolveServerHostnameCheckBox.TabIndex = 1;
this.ResolveServerHostnameCheckBox.Text = "Resolve Server Hostname";
this.ResolveServerHostnameCheckBox.UseVisualStyleBackColor = true;
//
// ServerPingTypeLabel
//
this.ServerPingTypeLabel.AutoSize = true;
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 44);
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 15);
this.ServerPingTypeLabel.Name = "ServerPingTypeLabel";
this.ServerPingTypeLabel.Size = new System.Drawing.Size(98, 17);
this.ServerPingTypeLabel.Size = new System.Drawing.Size(86, 17);
this.ServerPingTypeLabel.TabIndex = 2;
this.ServerPingTypeLabel.Text = "ServerPingType";
this.ServerPingTypeLabel.Text = "Ping Protocol";
//
// ICMPingRadioBtn
//
this.ICMPingRadioBtn.AutoSize = true;
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 63);
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 34);
this.ICMPingRadioBtn.Name = "ICMPingRadioBtn";
this.ICMPingRadioBtn.Size = new System.Drawing.Size(75, 21);
this.ICMPingRadioBtn.TabIndex = 3;
@@ -258,7 +245,7 @@ namespace Netch.Forms
// TCPingRadioBtn
//
this.TCPingRadioBtn.AutoSize = true;
this.TCPingRadioBtn.Location = new System.Drawing.Point(366, 64);
this.TCPingRadioBtn.Location = new System.Drawing.Point(366, 35);
this.TCPingRadioBtn.Name = "TCPingRadioBtn";
this.TCPingRadioBtn.Size = new System.Drawing.Size(66, 21);
this.TCPingRadioBtn.TabIndex = 4;
@@ -269,24 +256,24 @@ namespace Netch.Forms
// ProfileCountLabel
//
this.ProfileCountLabel.AutoSize = true;
this.ProfileCountLabel.Location = new System.Drawing.Point(12, 160);
this.ProfileCountLabel.Location = new System.Drawing.Point(15, 140);
this.ProfileCountLabel.Name = "ProfileCountLabel";
this.ProfileCountLabel.Size = new System.Drawing.Size(79, 17);
this.ProfileCountLabel.Size = new System.Drawing.Size(83, 17);
this.ProfileCountLabel.TabIndex = 5;
this.ProfileCountLabel.Text = "ProfileCount";
this.ProfileCountLabel.Text = "Profile Count";
//
// ProfileCountTextBox
//
this.ProfileCountTextBox.Location = new System.Drawing.Point(120, 157);
this.ProfileCountTextBox.Location = new System.Drawing.Point(182, 137);
this.ProfileCountTextBox.Name = "ProfileCountTextBox";
this.ProfileCountTextBox.Size = new System.Drawing.Size(90, 23);
this.ProfileCountTextBox.Size = new System.Drawing.Size(70, 23);
this.ProfileCountTextBox.TabIndex = 6;
this.ProfileCountTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// DetectionTickLabel
//
this.DetectionTickLabel.AutoSize = true;
this.DetectionTickLabel.Location = new System.Drawing.Point(225, 160);
this.DetectionTickLabel.Location = new System.Drawing.Point(15, 170);
this.DetectionTickLabel.Name = "DetectionTickLabel";
this.DetectionTickLabel.Size = new System.Drawing.Size(117, 17);
this.DetectionTickLabel.TabIndex = 7;
@@ -294,33 +281,33 @@ namespace Netch.Forms
//
// DetectionTickTextBox
//
this.DetectionTickTextBox.Location = new System.Drawing.Point(366, 157);
this.DetectionTickTextBox.Location = new System.Drawing.Point(182, 167);
this.DetectionTickTextBox.Name = "DetectionTickTextBox";
this.DetectionTickTextBox.Size = new System.Drawing.Size(68, 23);
this.DetectionTickTextBox.Size = new System.Drawing.Size(70, 23);
this.DetectionTickTextBox.TabIndex = 8;
this.DetectionTickTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// StartedPingLabel
//
this.StartedPingLabel.AutoSize = true;
this.StartedPingLabel.Location = new System.Drawing.Point(12, 187);
this.StartedPingLabel.Location = new System.Drawing.Point(15, 200);
this.StartedPingLabel.Name = "StartedPingLabel";
this.StartedPingLabel.Size = new System.Drawing.Size(126, 17);
this.StartedPingLabel.Size = new System.Drawing.Size(153, 17);
this.StartedPingLabel.TabIndex = 9;
this.StartedPingLabel.Text = "Delay test after start";
this.StartedPingLabel.Text = "Delay test after start(sec)";
//
// StartedPingIntervalTextBox
//
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(177, 184);
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(182, 197);
this.StartedPingIntervalTextBox.Name = "StartedPingIntervalTextBox";
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(68, 23);
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(70, 23);
this.StartedPingIntervalTextBox.TabIndex = 10;
this.StartedPingIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// STUNServerLabel
//
this.STUNServerLabel.AutoSize = true;
this.STUNServerLabel.Location = new System.Drawing.Point(12, 216);
this.STUNServerLabel.Location = new System.Drawing.Point(15, 230);
this.STUNServerLabel.Name = "STUNServerLabel";
this.STUNServerLabel.Size = new System.Drawing.Size(82, 17);
this.STUNServerLabel.TabIndex = 11;
@@ -329,34 +316,39 @@ namespace Netch.Forms
// STUN_ServerComboBox
//
this.STUN_ServerComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
this.STUN_ServerComboBox.Location = new System.Drawing.Point(120, 213);
this.STUN_ServerComboBox.Location = new System.Drawing.Point(182, 227);
this.STUN_ServerComboBox.Name = "STUN_ServerComboBox";
this.STUN_ServerComboBox.Size = new System.Drawing.Size(314, 25);
this.STUN_ServerComboBox.Size = new System.Drawing.Size(264, 25);
this.STUN_ServerComboBox.TabIndex = 12;
//
// LanguageLabel
//
this.LanguageLabel.AutoSize = true;
this.LanguageLabel.Location = new System.Drawing.Point(12, 254);
this.LanguageLabel.Location = new System.Drawing.Point(15, 260);
this.LanguageLabel.Name = "LanguageLabel";
this.LanguageLabel.Size = new System.Drawing.Size(65, 17);
this.LanguageLabel.TabIndex = 15;
this.LanguageLabel.TabIndex = 13;
this.LanguageLabel.Text = "Language";
//
// LanguageComboBox
//
this.LanguageComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.LanguageComboBox.FormattingEnabled = true;
this.LanguageComboBox.Location = new System.Drawing.Point(120, 251);
this.LanguageComboBox.Location = new System.Drawing.Point(182, 257);
this.LanguageComboBox.Name = "LanguageComboBox";
this.LanguageComboBox.Size = new System.Drawing.Size(121, 25);
this.LanguageComboBox.TabIndex = 16;
this.LanguageComboBox.Size = new System.Drawing.Size(110, 25);
this.LanguageComboBox.TabIndex = 14;
//
// NFTabPage
//
this.NFTabPage.BackColor = System.Drawing.SystemColors.ButtonFace;
this.NFTabPage.Controls.Add(this.groupBox1);
this.NFTabPage.Controls.Add(this.RedirectorSSCheckBox);
this.NFTabPage.Controls.Add(this.ProcessFilterProtocolLabel);
this.NFTabPage.Controls.Add(this.ProcessFilterProtocolComboBox);
this.NFTabPage.Controls.Add(this.DNSHijackCheckBox);
this.NFTabPage.Controls.Add(this.DNSHijackHostTextBox);
this.NFTabPage.Controls.Add(this.FilterICMPCheckBox);
this.NFTabPage.Controls.Add(this.ICMPDelayLabel);
this.NFTabPage.Controls.Add(this.ICMPDelayTextBox);
this.NFTabPage.Controls.Add(this.ChildProcessHandleCheckBox);
this.NFTabPage.Location = new System.Drawing.Point(4, 29);
this.NFTabPage.Name = "NFTabPage";
@@ -365,42 +357,28 @@ namespace Netch.Forms
this.NFTabPage.TabIndex = 1;
this.NFTabPage.Text = "Process Mode";
//
// groupBox1
// ProcessFilterProtocolLabel
//
this.groupBox1.Controls.Add(this.ProcessProxyProtocolLabel);
this.groupBox1.Controls.Add(this.ProcessProxyProtocolComboBox);
this.groupBox1.Controls.Add(this.DNSHijackCheckBox);
this.groupBox1.Controls.Add(this.DNSHijackHostTextBox);
this.groupBox1.Controls.Add(this.ICMPHijackCheckBox);
this.groupBox1.Controls.Add(this.ICMPHijackHostTextBox);
this.groupBox1.Location = new System.Drawing.Point(5, 6);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(450, 117);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.ProcessFilterProtocolLabel.AutoSize = true;
this.ProcessFilterProtocolLabel.Location = new System.Drawing.Point(30, 20);
this.ProcessFilterProtocolLabel.Name = "ProcessFilterProtocolLabel";
this.ProcessFilterProtocolLabel.Size = new System.Drawing.Size(89, 17);
this.ProcessFilterProtocolLabel.TabIndex = 0;
this.ProcessFilterProtocolLabel.Text = "Filter Protocol";
//
// ProcessProxyProtocolLabel
// ProcessFilterProtocolComboBox
//
this.ProcessProxyProtocolLabel.AutoSize = true;
this.ProcessProxyProtocolLabel.Location = new System.Drawing.Point(23, 21);
this.ProcessProxyProtocolLabel.Name = "ProcessProxyProtocolLabel";
this.ProcessProxyProtocolLabel.Size = new System.Drawing.Size(93, 17);
this.ProcessProxyProtocolLabel.TabIndex = 0;
this.ProcessProxyProtocolLabel.Text = "Proxy Protocol";
//
// ProcessProxyProtocolComboBox
//
this.ProcessProxyProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.ProcessProxyProtocolComboBox.FormattingEnabled = true;
this.ProcessProxyProtocolComboBox.Location = new System.Drawing.Point(118, 16);
this.ProcessProxyProtocolComboBox.Name = "ProcessProxyProtocolComboBox";
this.ProcessProxyProtocolComboBox.Size = new System.Drawing.Size(191, 25);
this.ProcessProxyProtocolComboBox.TabIndex = 1;
this.ProcessFilterProtocolComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.ProcessFilterProtocolComboBox.FormattingEnabled = true;
this.ProcessFilterProtocolComboBox.Location = new System.Drawing.Point(237, 17);
this.ProcessFilterProtocolComboBox.Name = "ProcessFilterProtocolComboBox";
this.ProcessFilterProtocolComboBox.Size = new System.Drawing.Size(98, 25);
this.ProcessFilterProtocolComboBox.TabIndex = 1;
//
// DNSHijackCheckBox
//
this.DNSHijackCheckBox.AutoSize = true;
this.DNSHijackCheckBox.Location = new System.Drawing.Point(6, 51);
this.DNSHijackCheckBox.Location = new System.Drawing.Point(15, 50);
this.DNSHijackCheckBox.Name = "DNSHijackCheckBox";
this.DNSHijackCheckBox.Size = new System.Drawing.Size(196, 21);
this.DNSHijackCheckBox.TabIndex = 2;
@@ -410,51 +388,48 @@ namespace Netch.Forms
// DNSHijackHostTextBox
//
this.DNSHijackHostTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.DNSHijackCheckBox, "Checked", true));
this.DNSHijackHostTextBox.Location = new System.Drawing.Point(253, 46);
this.DNSHijackHostTextBox.Location = new System.Drawing.Point(237, 48);
this.DNSHijackHostTextBox.Name = "DNSHijackHostTextBox";
this.DNSHijackHostTextBox.Size = new System.Drawing.Size(191, 23);
this.DNSHijackHostTextBox.TabIndex = 4;
this.DNSHijackHostTextBox.TabIndex = 3;
this.DNSHijackHostTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// ICMPHijackCheckBox
// FilterICMPCheckBox
//
this.ICMPHijackCheckBox.AutoSize = true;
this.ICMPHijackCheckBox.Enabled = false;
this.ICMPHijackCheckBox.Location = new System.Drawing.Point(6, 81);
this.ICMPHijackCheckBox.Name = "ICMPHijackCheckBox";
this.ICMPHijackCheckBox.Size = new System.Drawing.Size(139, 21);
this.ICMPHijackCheckBox.TabIndex = 5;
this.ICMPHijackCheckBox.Text = "Global ICMP Hijack";
this.ICMPHijackCheckBox.UseVisualStyleBackColor = true;
this.FilterICMPCheckBox.AutoSize = true;
this.FilterICMPCheckBox.Location = new System.Drawing.Point(13, 80);
this.FilterICMPCheckBox.Name = "FilterICMPCheckBox";
this.FilterICMPCheckBox.Size = new System.Drawing.Size(90, 21);
this.FilterICMPCheckBox.TabIndex = 4;
this.FilterICMPCheckBox.Text = "Filter ICMP";
this.FilterICMPCheckBox.UseVisualStyleBackColor = true;
//
// ICMPHijackHostTextBox
// ICMPDelayLabel
//
this.ICMPHijackHostTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.ICMPHijackCheckBox, "Checked", true));
this.ICMPHijackHostTextBox.Enabled = false;
this.ICMPHijackHostTextBox.Location = new System.Drawing.Point(253, 78);
this.ICMPHijackHostTextBox.Name = "ICMPHijackHostTextBox";
this.ICMPHijackHostTextBox.Size = new System.Drawing.Size(191, 23);
this.ICMPHijackHostTextBox.TabIndex = 7;
this.ICMPHijackHostTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.ICMPDelayLabel.AutoSize = true;
this.ICMPDelayLabel.Location = new System.Drawing.Point(30, 110);
this.ICMPDelayLabel.Name = "ICMPDelayLabel";
this.ICMPDelayLabel.Size = new System.Drawing.Size(100, 17);
this.ICMPDelayLabel.TabIndex = 5;
this.ICMPDelayLabel.Text = "ICMP Delay(ms)";
//
// RedirectorSSCheckBox
// ICMPDelayTextBox
//
this.RedirectorSSCheckBox.AutoSize = true;
this.RedirectorSSCheckBox.Location = new System.Drawing.Point(11, 129);
this.RedirectorSSCheckBox.Name = "RedirectorSSCheckBox";
this.RedirectorSSCheckBox.Size = new System.Drawing.Size(106, 21);
this.RedirectorSSCheckBox.TabIndex = 1;
this.RedirectorSSCheckBox.Text = "Redirector SS";
this.RedirectorSSCheckBox.UseVisualStyleBackColor = true;
this.ICMPDelayTextBox.Location = new System.Drawing.Point(237, 107);
this.ICMPDelayTextBox.Name = "ICMPDelayTextBox";
this.ICMPDelayTextBox.ReadOnly = true;
this.ICMPDelayTextBox.Size = new System.Drawing.Size(98, 23);
this.ICMPDelayTextBox.TabIndex = 6;
this.ICMPDelayTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// ChildProcessHandleCheckBox
//
this.ChildProcessHandleCheckBox.AutoSize = true;
this.ChildProcessHandleCheckBox.Enabled = false;
this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(11, 151);
this.ChildProcessHandleCheckBox.Location = new System.Drawing.Point(15, 140);
this.ChildProcessHandleCheckBox.Name = "ChildProcessHandleCheckBox";
this.ChildProcessHandleCheckBox.Size = new System.Drawing.Size(150, 21);
this.ChildProcessHandleCheckBox.TabIndex = 2;
this.ChildProcessHandleCheckBox.TabIndex = 8;
this.ChildProcessHandleCheckBox.Text = "Child Process Handle";
this.ChildProcessHandleCheckBox.UseVisualStyleBackColor = true;
//
@@ -773,6 +748,7 @@ namespace Netch.Forms
this.OtherTabPage.Controls.Add(this.StopWhenExitedCheckBox);
this.OtherTabPage.Controls.Add(this.StartWhenOpenedCheckBox);
this.OtherTabPage.Controls.Add(this.MinimizeWhenStartedCheckBox);
this.OtherTabPage.Controls.Add(this.NoSupportDialogCheckBox);
this.OtherTabPage.Controls.Add(this.RunAtStartupCheckBox);
this.OtherTabPage.Controls.Add(this.CheckUpdateWhenOpenedCheckBox);
this.OtherTabPage.Controls.Add(this.CheckBetaUpdateCheckBox);
@@ -827,6 +803,16 @@ namespace Netch.Forms
this.MinimizeWhenStartedCheckBox.Text = "Minimize when started";
this.MinimizeWhenStartedCheckBox.UseVisualStyleBackColor = true;
//
// NoSupportDialogCheckBox
//
this.NoSupportDialogCheckBox.AutoSize = true;
this.NoSupportDialogCheckBox.Location = new System.Drawing.Point(6, 72);
this.NoSupportDialogCheckBox.Name = "NoSupportDialogCheckBox";
this.NoSupportDialogCheckBox.Size = new System.Drawing.Size(174, 21);
this.NoSupportDialogCheckBox.TabIndex = 4;
this.NoSupportDialogCheckBox.Text = "Disable Support Warning";
this.NoSupportDialogCheckBox.UseVisualStyleBackColor = true;
//
// RunAtStartupCheckBox
//
this.RunAtStartupCheckBox.AutoSize = true;
@@ -872,12 +858,12 @@ namespace Netch.Forms
//
// AioDNSTabPage
//
this.AioDNSTabPage.Controls.Add(this.AioDNSRuleRuleLabel);
this.AioDNSTabPage.Controls.Add(this.AioDNSRulePathTextBox);
this.AioDNSTabPage.Controls.Add(this.ChinaDNSLabel);
this.AioDNSTabPage.Controls.Add(this.ChinaDNSTextBox);
this.AioDNSTabPage.Controls.Add(this.OtherDNSLabel);
this.AioDNSTabPage.Controls.Add(this.OtherDNSTextBox);
this.AioDNSTabPage.Controls.Add(this.AioDNSListenPortLabel);
this.AioDNSTabPage.Controls.Add(this.AioDNSListenPortTextBox);
this.AioDNSTabPage.Location = new System.Drawing.Point(4, 29);
this.AioDNSTabPage.Name = "AioDNSTabPage";
this.AioDNSTabPage.Padding = new System.Windows.Forms.Padding(3);
@@ -886,57 +872,57 @@ namespace Netch.Forms
this.AioDNSTabPage.Text = "AioDNS";
this.AioDNSTabPage.UseVisualStyleBackColor = true;
//
// AioDNSRuleRuleLabel
//
this.AioDNSRuleRuleLabel.AutoSize = true;
this.AioDNSRuleRuleLabel.Location = new System.Drawing.Point(16, 30);
this.AioDNSRuleRuleLabel.Name = "AioDNSRuleRuleLabel";
this.AioDNSRuleRuleLabel.Size = new System.Drawing.Size(56, 17);
this.AioDNSRuleRuleLabel.TabIndex = 0;
this.AioDNSRuleRuleLabel.Text = "Rule File";
//
// AioDNSRulePathTextBox
//
this.AioDNSRulePathTextBox.Enabled = false;
this.AioDNSRulePathTextBox.Location = new System.Drawing.Point(150, 30);
this.AioDNSRulePathTextBox.Name = "AioDNSRulePathTextBox";
this.AioDNSRulePathTextBox.Size = new System.Drawing.Size(201, 23);
this.AioDNSRulePathTextBox.TabIndex = 1;
//
// ChinaDNSLabel
//
this.ChinaDNSLabel.AutoSize = true;
this.ChinaDNSLabel.Location = new System.Drawing.Point(16, 70);
this.ChinaDNSLabel.Location = new System.Drawing.Point(15, 23);
this.ChinaDNSLabel.Name = "ChinaDNSLabel";
this.ChinaDNSLabel.Size = new System.Drawing.Size(70, 17);
this.ChinaDNSLabel.TabIndex = 2;
this.ChinaDNSLabel.TabIndex = 0;
this.ChinaDNSLabel.Text = "China DNS";
//
// ChinaDNSTextBox
//
this.ChinaDNSTextBox.Location = new System.Drawing.Point(150, 70);
this.ChinaDNSTextBox.Location = new System.Drawing.Point(150, 20);
this.ChinaDNSTextBox.Name = "ChinaDNSTextBox";
this.ChinaDNSTextBox.Size = new System.Drawing.Size(201, 23);
this.ChinaDNSTextBox.TabIndex = 3;
this.ChinaDNSTextBox.TabIndex = 1;
this.ChinaDNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// OtherDNSLabel
//
this.OtherDNSLabel.AutoSize = true;
this.OtherDNSLabel.Location = new System.Drawing.Point(16, 110);
this.OtherDNSLabel.Location = new System.Drawing.Point(15, 63);
this.OtherDNSLabel.Name = "OtherDNSLabel";
this.OtherDNSLabel.Size = new System.Drawing.Size(71, 17);
this.OtherDNSLabel.TabIndex = 4;
this.OtherDNSLabel.TabIndex = 2;
this.OtherDNSLabel.Text = "Other DNS";
//
// OtherDNSTextBox
//
this.OtherDNSTextBox.Location = new System.Drawing.Point(150, 110);
this.OtherDNSTextBox.Location = new System.Drawing.Point(150, 60);
this.OtherDNSTextBox.Name = "OtherDNSTextBox";
this.OtherDNSTextBox.Size = new System.Drawing.Size(201, 23);
this.OtherDNSTextBox.TabIndex = 5;
this.OtherDNSTextBox.TabIndex = 3;
this.OtherDNSTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// AioDNSListenPortLabel
//
this.AioDNSListenPortLabel.AutoSize = true;
this.AioDNSListenPortLabel.Location = new System.Drawing.Point(15, 103);
this.AioDNSListenPortLabel.Name = "AioDNSListenPortLabel";
this.AioDNSListenPortLabel.Size = new System.Drawing.Size(69, 17);
this.AioDNSListenPortLabel.TabIndex = 4;
this.AioDNSListenPortLabel.Text = "Listen Port";
//
// AioDNSListenPortTextBox
//
this.AioDNSListenPortTextBox.Location = new System.Drawing.Point(150, 100);
this.AioDNSListenPortTextBox.Name = "AioDNSListenPortTextBox";
this.AioDNSListenPortTextBox.Size = new System.Drawing.Size(80, 23);
this.AioDNSListenPortTextBox.TabIndex = 5;
this.AioDNSListenPortTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// ControlButton
//
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@@ -982,8 +968,6 @@ namespace Netch.Forms
this.PortGroupBox.PerformLayout();
this.NFTabPage.ResumeLayout(false);
this.NFTabPage.PerformLayout();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.WinTUNTabPage.ResumeLayout(false);
this.WinTUNGroupBox.ResumeLayout(false);
this.WinTUNGroupBox.PerformLayout();
@@ -1016,7 +1000,6 @@ namespace Netch.Forms
private System.Windows.Forms.TextBox HTTPPortTextBox;
private System.Windows.Forms.Label Socks5PortLabel;
private System.Windows.Forms.TextBox Socks5PortTextBox;
private System.Windows.Forms.CheckBox ResolveServerHostnameCheckBox;
private System.Windows.Forms.GroupBox WinTUNGroupBox;
private System.Windows.Forms.CheckBox ProxyDNSCheckBox;
private System.Windows.Forms.CheckBox UseCustomDNSCheckBox;
@@ -1067,22 +1050,22 @@ namespace Netch.Forms
private System.Windows.Forms.TextBox ttiTextBox;
private System.Windows.Forms.CheckBox UseMuxCheckBox;
private System.Windows.Forms.TabPage AioDNSTabPage;
private System.Windows.Forms.Label AioDNSRuleRuleLabel;
private System.Windows.Forms.TextBox AioDNSRulePathTextBox;
private System.Windows.Forms.Label AioDNSListenPortLabel;
private System.Windows.Forms.TextBox AioDNSListenPortTextBox;
private System.Windows.Forms.Label OtherDNSLabel;
private System.Windows.Forms.Label ChinaDNSLabel;
private System.Windows.Forms.TextBox OtherDNSTextBox;
private System.Windows.Forms.TextBox ChinaDNSTextBox;
private System.Windows.Forms.TextBox DNSHijackHostTextBox;
private System.Windows.Forms.CheckBox RedirectorSSCheckBox;
private System.Windows.Forms.Label ServerPingTypeLabel;
private System.Windows.Forms.RadioButton TCPingRadioBtn;
private System.Windows.Forms.RadioButton ICMPingRadioBtn;
private System.Windows.Forms.ComboBox ProcessProxyProtocolComboBox;
private System.Windows.Forms.Label ProcessProxyProtocolLabel;
private System.Windows.Forms.CheckBox ICMPHijackCheckBox;
private System.Windows.Forms.ComboBox ProcessFilterProtocolComboBox;
private System.Windows.Forms.Label ProcessFilterProtocolLabel;
private System.Windows.Forms.CheckBox FilterICMPCheckBox;
private System.Windows.Forms.CheckBox ChildProcessHandleCheckBox;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.TextBox ICMPHijackHostTextBox;
private System.Windows.Forms.TextBox ICMPDelayTextBox;
private System.Windows.Forms.Label ICMPDelayLabel;
private System.Windows.Forms.CheckBox NoSupportDialogCheckBox;
}
}

View File

@@ -8,6 +8,7 @@ using System.Windows.Forms;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using Serilog;
namespace Netch.Forms
{
@@ -37,9 +38,7 @@ namespace Netch.Forms
BindCheckBox(AllowDevicesCheckBox,
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
Global.Settings.LocalAddress switch {"127.0.0.1" => false, "0.0.0.0" => true, _ => false});
BindCheckBox(ResolveServerHostnameCheckBox, c => Global.Settings.ResolveServerHostname = c, Global.Settings.ResolveServerHostname);
Global.Settings.LocalAddress switch { "127.0.0.1" => false, "0.0.0.0" => true, _ => false });
BindRadioBox(ICMPingRadioBtn, _ => { }, !Global.Settings.ServerTCPing);
@@ -47,7 +46,7 @@ namespace Netch.Forms
BindTextBox<int>(ProfileCountTextBox, i => i > -1, i => Global.Settings.ProfileCount = i, Global.Settings.ProfileCount);
BindTextBox<int>(DetectionTickTextBox,
i => ServerHelper.DelayTestHelper.Range.InRange(i),
i => DelayTestHelper.Range.InRange(i),
i => Global.Settings.DetectionTick = i,
Global.Settings.DetectionTick);
@@ -59,11 +58,11 @@ namespace Netch.Forms
object[]? stuns;
try
{
stuns = File.ReadLines("bin\\stun.txt").Cast<object>().ToArray();
stuns = File.ReadLines(Constants.STUNServersFile).Cast<object>().ToArray();
}
catch (Exception e)
{
Logging.Warning($"Load stun.txt failed: {e.Message}");
Log.Warning(e, "Load stun.txt failed");
stuns = null;
}
@@ -98,28 +97,23 @@ namespace Netch.Forms
#region Process Mode
BindListComboBox(ProcessFilterProtocolComboBox,
s => Global.Settings.Redirector.FilterProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
Enum.GetNames(typeof(PortType)),
Global.Settings.Redirector.FilterProtocol.ToString());
BindCheckBox(DNSHijackCheckBox, b => Global.Settings.Redirector.DNSHijack = b, Global.Settings.Redirector.DNSHijack);
BindTextBox(DNSHijackHostTextBox, s => true, s => Global.Settings.Redirector.DNSHijackHost = s, Global.Settings.Redirector.DNSHijackHost);
BindCheckBox(ICMPHijackCheckBox, b => Global.Settings.Redirector.ICMPHijack = b, Global.Settings.Redirector.ICMPHijack);
BindCheckBox(FilterICMPCheckBox, b => Global.Settings.Redirector.FilterICMP = b, Global.Settings.Redirector.FilterICMP);
BindTextBox(ICMPHijackHostTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.Redirector.ICMPHost = s,
Global.Settings.Redirector.ICMPHost);
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.Redirector.RedirectorSS = s, Global.Settings.Redirector.RedirectorSS);
BindTextBox(ICMPDelayTextBox, s => int.TryParse(s, out _), s => { }, Global.Settings.Redirector.ICMPDelay);
BindCheckBox(ChildProcessHandleCheckBox,
s => Global.Settings.Redirector.ChildProcessHandle = s,
Global.Settings.Redirector.ChildProcessHandle);
BindListComboBox(ProcessProxyProtocolComboBox,
s => Global.Settings.Redirector.ProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
Enum.GetNames(typeof(PortType)),
Global.Settings.Redirector.ProxyProtocol.ToString());
#endregion
#region TUN/TAP
@@ -207,16 +201,21 @@ namespace Netch.Forms
BindCheckBox(UpdateServersWhenOpenedCheckBox, b => Global.Settings.UpdateServersWhenOpened = b, Global.Settings.UpdateServersWhenOpened);
BindCheckBox(NoSupportDialogCheckBox, b => Global.Settings.NoSupportDialog = b, Global.Settings.NoSupportDialog);
#endregion
#region AioDNS
BindTextBox(AioDNSRulePathTextBox, _ => true, s => Global.Settings.AioDNS.RulePath = s, Global.Settings.AioDNS.RulePath);
BindTextBox(ChinaDNSTextBox, _ => true, s => Global.Settings.AioDNS.ChinaDNS = s, Global.Settings.AioDNS.ChinaDNS);
BindTextBox(OtherDNSTextBox, _ => true, s => Global.Settings.AioDNS.OtherDNS = s, Global.Settings.AioDNS.OtherDNS);
BindTextBox(AioDNSListenPortTextBox,
s => ushort.TryParse(s, out _),
s => Global.Settings.AioDNS.ListenPort = ushort.Parse(s),
Global.Settings.AioDNS.ListenPort);
#endregion
}
@@ -240,7 +239,7 @@ namespace Netch.Forms
Show();
}
private void ControlButton_Click(object sender, EventArgs e)
private async void ControlButton_Click(object sender, EventArgs e)
{
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
@@ -264,7 +263,7 @@ namespace Netch.Forms
Utils.Utils.RegisterNetchStartupItem();
Configuration.Save();
await Configuration.SaveAsync();
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}
@@ -284,7 +283,7 @@ namespace Netch.Forms
{
try
{
return check.Invoke((T) Convert.ChangeType(s, typeof(T)));
return check.Invoke((T)Convert.ChangeType(s, typeof(T)));
}
catch
{
@@ -292,19 +291,19 @@ namespace Netch.Forms
}
});
_saveActions.Add(control, c => save.Invoke((T) Convert.ChangeType(((TextBox) c).Text, typeof(T))));
_saveActions.Add(control, c => save.Invoke((T)Convert.ChangeType(((TextBox)c).Text, typeof(T))));
}
private void BindCheckBox(CheckBox control, Action<bool> save, bool value)
{
control.Checked = value;
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
_saveActions.Add(control, c => save.Invoke(((CheckBox)c).Checked));
}
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
{
control.Checked = value;
_saveActions.Add(control, c => save.Invoke(((RadioButton) c).Checked));
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
}
private void BindListComboBox<T>(ComboBox comboBox, Action<T> save, IEnumerable<T> values, T value) where T : notnull
@@ -318,7 +317,7 @@ namespace Netch.Forms
comboBox.ValueMember = nameof(TagItem<T>.Value);
comboBox.DisplayMember = nameof(TagItem<T>.Text);
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>) ((ComboBox) c).SelectedItem).Value));
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>)((ComboBox)c).SelectedItem).Value));
Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); };
}
@@ -327,7 +326,7 @@ namespace Netch.Forms
if (values != null)
control.Items.AddRange(values);
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).Text));
_saveActions.Add(control, c => save.Invoke(((ComboBox)c).Text));
_checkActions.Add(control, check.Invoke);
Load += (_, _) => { control.Text = value; };

View File

@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Windows.Forms;
using Netch.Models;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using System;
using System.Linq;
using System.Windows.Forms;
namespace Netch.Forms
{
@@ -57,9 +57,9 @@ namespace Netch.Forms
Global.Settings.SubscribeLink[index].Enable = SubscribeLinkListView.Items[index].Checked;
}
private void SubscribeForm_FormClosing(object sender, FormClosingEventArgs e)
private async void SubscribeForm_FormClosing(object sender, FormClosingEventArgs e)
{
Configuration.Save();
await Configuration.SaveAsync();
}
#endregion

View File

@@ -25,19 +25,25 @@ namespace Netch
/// </summary>
public static readonly List<Mode> Modes = new();
public static readonly string NetchDir;
public static readonly string NetchExecutable;
static Global()
{
NetchExecutable = Application.ExecutablePath;
NetchDir = Application.StartupPath;
}
/// <summary>
/// 主窗体的静态实例
/// </summary>
public static MainForm MainForm => LazyMainForm.Value;
public static JsonSerializerOptions NewDefaultJsonSerializerOptions => new()
public static JsonSerializerOptions NewCustomJsonSerializerOptions() => new()
{
WriteIndented = true,
IgnoreNullValues = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
public static readonly string NetchDir = Application.StartupPath;
public static readonly string NetchExecutable = Application.ExecutablePath;
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Netch.Interfaces
{
public interface IController
{
public string Name { get; }
public Task StopAsync();
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Netch.Models;
using Netch.Servers;
namespace Netch.Interfaces
{
public interface IModeController : IController
{
public Task StartAsync(Socks5Server server, Mode mode);
}
}

View File

@@ -1,6 +1,8 @@
using Netch.Models;
using System.Threading.Tasks;
using Netch.Models;
using Netch.Servers;
namespace Netch.Controllers
namespace Netch.Interfaces
{
public interface IServerController : IController
{
@@ -8,13 +10,7 @@ namespace Netch.Controllers
public string? LocalAddress { get; set; }
/// <summary>
/// 启动
/// </summary>
/// <param name="s">服务器</param>
/// <param name="mode">模式</param>
/// <returns>是否启动成功</returns>
public abstract void Start(in Server s, in Mode mode);
public Task<Socks5LocalServer> StartAsync(Server s);
}
public static class ServerControllerExtension

View File

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

View File

@@ -1,17 +1,30 @@
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Serilog;
namespace Netch.Interops
{
public static class AioDNSInterops
public static class AioDNS
{
private const string aiodns_bin = "aiodns.bin";
public static bool Dial(NameList name, string value)
{
Log.Verbose($"[aiodns] Dial {name}: {value}");
return aiodns_dial(name, Encoding.UTF8.GetBytes(value));
}
public static async Task<bool> InitAsync()
{
return await Task.Run(Init).ConfigureAwait(false);
}
public static async Task FreeAsync()
{
await Task.Run(Free).ConfigureAwait(false);
}
[DllImport(aiodns_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool aiodns_dial(NameList name, byte[] value);

15
Netch/Interops/NFAPI.cs Normal file
View File

@@ -0,0 +1,15 @@
using System.Runtime.InteropServices;
namespace Netch.Interops
{
public static class NFAPI
{
private const string nfapinet_bin = "nfapinet.dll";
[DllImport(nfapinet_bin, CallingConvention = CallingConvention.Cdecl)]
public static extern NF_STATUS nf_registerDriver(string driverName);
[DllImport(nfapinet_bin, CallingConvention = CallingConvention.Cdecl)]
public static extern NF_STATUS nf_unRegisterDriver(string driverName);
}
}

View File

@@ -0,0 +1,11 @@
namespace Netch.Interops
{
public enum NF_STATUS : int
{
NF_STATUS_SUCCESS = 0,
NF_STATUS_FAIL = -1,
NF_STATUS_INVALID_ENDPOINT_ID = -2,
NF_STATUS_NOT_INITIALIZED = -3,
NF_STATUS_IO_ERROR = -4
}
}

View File

@@ -1,18 +1,22 @@
using System.Runtime.InteropServices;
using Netch.Utils;
using System.Threading.Tasks;
using Serilog;
namespace Netch.Interops
{
public static class RedirectorInterop
public static class Redirector
{
public enum NameList
{
TYPE_FILTLOP,
TYPE_FILTTCP,
TYPE_FILTUDP,
TYPE_FILTERLOOPBACK,
TYPE_FILTERICMP,
TYPE_FILTERTCP,
TYPE_FILTERUDP,
TYPE_CLRNAME,
TYPE_ADDNAME,
TYPE_BYPNAME,
TYPE_DNSHOST,
TYPE_TCPLISN,
@@ -40,21 +44,21 @@ namespace Netch.Interops
public static bool Dial(NameList name, string value)
{
Logging.Debug($"Dial {name} {value}");
Log.Verbose($"[Redirector] Dial {name}: {value}");
return aio_dial(name, value);
}
public static bool Init()
public static async Task<bool> InitAsync()
{
return aio_init();
return await Task.Run(aio_init).ConfigureAwait(false);
}
public static bool Free()
public static async Task<bool> FreeAsync()
{
return aio_free();
return await Task.Run(aio_free).ConfigureAwait(false);
}
public const int UdpNameListOffset = (int) NameList.TYPE_UDPLISN - (int) NameList.TYPE_TCPLISN;
public const int UdpNameListOffset = (int)NameList.TYPE_UDPLISN - (int)NameList.TYPE_TCPLISN;
private const string Redirector_bin = "Redirector.bin";

View File

@@ -0,0 +1,26 @@
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace Netch.Interops
{
public static class RouteHelper
{
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong ConvertLuidToIndex(ulong id);
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool CreateIPv4(string address, string netmask, ulong index);
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool RefreshIPTable(AddressFamily inet, ulong index);
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool CreateRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool DeleteRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
}
}

View File

@@ -1,10 +1,11 @@
using System.Runtime.InteropServices;
using System.Text;
using Netch.Utils;
using System.Threading.Tasks;
using Serilog;
namespace Netch.Interops
{
public static class TUNInterop
public static class tun2socks
{
public enum NameList
{
@@ -36,18 +37,19 @@ namespace Netch.Interops
public static bool Dial(NameList name, string value)
{
Logging.Debug($"Dial {name} {value}");
Log.Verbose( $"[tun2socks] Dial {name}: {value}");
return tun_dial(name, Encoding.UTF8.GetBytes(value));
}
public static bool Init()
{
Log.Verbose("[tun2socks] init");
return tun_init();
}
public static bool Free()
public static async Task<bool> FreeAsync()
{
return tun_free();
return await Task.Run(tun_free).ConfigureAwait(false);
}
private const string tun2socks_bin = "tun2socks.bin";
@@ -62,7 +64,7 @@ namespace Netch.Interops
private static extern bool tun_free();
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern ulong tun_luid();
public static extern ulong tun_luid();
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern ulong tun_getUP();

49
Netch/Models/Arguments.cs Normal file
View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Netch.Utils;
namespace Netch.Models
{
public static class Arguments
{
public static string Format(IEnumerable<object?> a)
{
var arguments = a.ToList();
if (arguments.Count % 2 != 0)
throw new FormatException("missing last argument value");
var tokens = new List<string>();
for (var i = 0; i < arguments.Count; i += 2)
{
var keyObj = arguments[i];
var valueObj = arguments[i + 1];
if (keyObj is not string key)
throw new FormatException($"argument key at array index {i} is not string");
switch (valueObj)
{
case SpecialArgument.Flag:
tokens.Add(key);
break;
case null:
case string value when value.IsNullOrWhiteSpace():
continue;
default:
tokens.Add(key);
tokens.Add(valueObj.ToString()!);
break;
}
}
return string.Join(' ', tokens);
}
}
public enum SpecialArgument
{
Flag
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
namespace Netch.Models
{
public struct NatTypeTestResult
{
public string? Result;
public string? LocalEnd;
public string? PublicEnd;
}
}

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

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

View File

@@ -1,12 +1,12 @@
namespace Netch.Models
{
public readonly struct Range
public readonly struct NumberRange
{
public int Start { get; }
public int End { get; }
public Range(int start, int end)
public NumberRange(int start, int end)
{
Start = start;
End = end;

View File

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

View File

@@ -1,121 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using Netch.Utils;
namespace Netch.Models
{
public abstract class ParameterBase
{
// null value par
private readonly bool _full;
protected readonly string ParametersSeparate = " ";
protected readonly string Separate = " ";
protected readonly string VerbPrefix = "-";
protected readonly string FullPrefix = "--";
protected ParameterBase()
{
_full = !GetType().IsDefined(typeof(VerbAttribute));
}
public override string ToString()
{
var parameters = GetType().GetProperties().Select(PropToParameter).Where(s => s != null).Cast<string>();
return string.Join(ParametersSeparate, parameters).Trim();
}
private string? PropToParameter(PropertyInfo p)
{
// prefix
bool full;
if (p.IsDefined(typeof(VerbAttribute)))
full = false;
else if (p.IsDefined(typeof(FullAttribute)))
full = true;
else
full = _full;
var prefix = full ? FullPrefix : VerbPrefix;
// key
var key = p.GetCustomAttribute<RealNameAttribute>()?.Name ?? p.Name;
// build
var value = p.GetValue(this);
switch (value)
{
case bool b:
return b ? $"{prefix}{key}" : null;
default:
if ((value?.ToString() ?? null).IsNullOrWhiteSpace())
return p.IsDefined(typeof(OptionalAttribute)) ? null : throw new RequiredArgumentValueInvalidException(p.Name, this, null);
if (p.IsDefined(typeof(QuoteAttribute)))
value = $"\"{value}\"";
return $"{prefix}{key}{Separate}{value}";
}
}
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
public class VerbAttribute : Attribute
{
// Don't use verb and full both on one class or property
// if you did, will take verb
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
public class FullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class OptionalAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class QuoteAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class RealNameAttribute : Attribute
{
public string Name { get; }
public RealNameAttribute(string name)
{
Name = name;
}
}
[Serializable]
public class RequiredArgumentValueInvalidException : Exception
{
public string? ArgumentName { get; }
public object? ArgumentObject { get; }
private readonly string? _message;
private const string DefaultMessage = "{0}'s Argument \"{1}\" value invalid. A required argument's value can't be null or empty.";
public override string Message => _message ?? string.Format(DefaultMessage, ArgumentObject!.GetType(), ArgumentName);
public RequiredArgumentValueInvalidException()
{
_message = "Some Argument value invalid. A required argument value's can't be null or empty.";
}
public RequiredArgumentValueInvalidException(string argumentName, object argumentObject, string? message)
{
ArgumentName = argumentName;
ArgumentObject = argumentObject;
_message = message;
}
}
}

View File

@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Netch.Utils;
namespace Netch.Models
{
public class Server : ICloneable
public abstract class Server : ICloneable
{
/// <summary>
/// 延迟
@@ -17,7 +17,7 @@ namespace Netch.Models
/// <summary>
/// 组
/// </summary>
public string Group { get; set; } = "None";
public string Group { get; set; } = Constants.DefaultGroup;
/// <summary>
/// 地址
@@ -42,11 +42,7 @@ namespace Netch.Models
/// <summary>
/// 代理类型
/// </summary>
public virtual string Type { get; } = string.Empty;
[JsonExtensionData]
// ReSharper disable once CollectionNeverUpdated.Global
public Dictionary<string, object> ExtensionData { get; set; } = new();
public abstract string Type { get; }
public object Clone()
{
@@ -61,55 +57,48 @@ namespace Netch.Models
{
var remark = string.IsNullOrWhiteSpace(Remark) ? $"{Hostname}:{Port}" : Remark;
if (Group.Equals("None") || Group.Equals(""))
Group = "NONE";
string shortName;
if (Type == string.Empty)
{
shortName = "WTF";
}
else
{
shortName = ServerHelper.GetUtilByTypeName(Type).ShortName;
}
var shortName = ServerHelper.GetUtilByTypeName(Type).ShortName;
return $"[{shortName}][{Group}] {remark}";
}
public abstract string MaskedData();
/// <summary>
/// 测试延迟
/// </summary>
/// <returns>延迟</returns>
public int Test()
public async Task<int> PingAsync()
{
try
{
var destination = DnsUtils.Lookup(Hostname);
var destination = await DnsUtils.LookupAsync(Hostname);
if (destination == null)
return Delay = -2;
var list = new Task<int>[3];
for (var i = 0; i < 3; i++)
list[i] = Task.Run(async () =>
{
async Task<int> PingCoreAsync()
{
try
{
return Global.Settings.ServerTCPing
? await Utils.Utils.TCPingAsync(destination, Port)
: Utils.Utils.ICMPing(destination, Port);
: await Utils.Utils.ICMPingAsync(destination);
}
catch (Exception)
{
return -4;
}
});
}
Task.WaitAll(list[0], list[1], list[2]);
list[i] = PingCoreAsync();
}
var min = Math.Min(list[0].Result, list[1].Result);
min = Math.Min(min, list[2].Result);
return Delay = min;
var resTask = await Task.WhenAny(list[0], list[1], list[2]);
return Delay = await resTask;
}
catch (Exception)
{
@@ -120,22 +109,15 @@ namespace Netch.Models
public static class ServerExtension
{
public static string AutoResolveHostname(this Server server)
public static async Task<string> AutoResolveHostnameAsync(this Server server, AddressFamily inet = AddressFamily.Unspecified)
{
return Global.Settings.ResolveServerHostname ? DnsUtils.Lookup(server.Hostname)!.ToString() : server.Hostname;
// ! MainController cached
return (await DnsUtils.LookupAsync(server.Hostname, inet))!.ToString();
}
public static bool Valid(this Server server)
public static bool IsInGroup(this Server server)
{
try
{
ServerHelper.GetTypeByTypeName(server.Type);
return true;
}
catch
{
return false;
}
return server.Group is not Constants.DefaultGroup;
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Netch.Utils;
namespace Netch.Models
@@ -36,7 +37,7 @@ namespace Netch.Models
/// <summary>
/// 使用自定义 DNS 设置
/// </summary>
public bool UseCustomDNS { get; set; } = true;
public bool UseCustomDNS { get; set; } = false;
/// <summary>
/// 全局绕过 IP 列表
@@ -71,7 +72,7 @@ namespace Netch.Models
public bool V2rayNShareLink { get; set; } = true;
public bool XrayCone { get; set; } = false;
public bool XrayCone { get; set; } = true;
}
public class AioDNSConfig
@@ -80,9 +81,7 @@ namespace Netch.Models
public string OtherDNS { get; set; } = "tcp://1.1.1.1:53";
public ushort ListenPort { get; set; } = 53;
public string RulePath { get; set; } = "bin\\aiodns.conf";
public ushort ListenPort { get; set; } = 253;
}
public class RedirectorConfig
@@ -90,7 +89,7 @@ namespace Netch.Models
/// <summary>
/// 不代理TCP
/// </summary>
public PortType ProxyProtocol { get; set; } = PortType.Both;
public PortType FilterProtocol { get; set; } = PortType.Both;
/// <summary>
/// 是否开启DNS转发
@@ -102,18 +101,15 @@ namespace Netch.Models
/// </summary>
public string DNSHijackHost { get; set; } = "1.1.1.1:53";
public string ICMPHost { get; set; } = "1.2.4.8";
[JsonIgnore]
public int ICMPDelay { get; } = 0;
public bool ICMPHijack { get; set; } = false;
/// <summary>
/// 是否使用RDR内置SS
/// </summary>
public bool RedirectorSS { get; set; } = false;
public bool FilterICMP { get; set; } = false;
/// <summary>
/// 是否代理子进程
/// </summary>
[JsonIgnore]
public bool ChildProcessHandle { get; set; } = false;
}
@@ -196,11 +192,6 @@ namespace Netch.Models
/// </summary>
public int RequestTimeout { get; set; } = 10000;
/// <summary>
/// 解析服务器主机名
/// </summary>
public bool ResolveServerHostname { get; set; } = true;
/// <summary>
/// 是否开机启动软件
/// </summary>
@@ -263,9 +254,11 @@ namespace Netch.Models
public V2rayConfig V2RayConfig { get; set; } = new();
public bool NoSupportDialog { get; set; } = false;
public Setting Clone()
{
return (Setting) MemberwiseClone();
return (Setting)MemberwiseClone();
}
public void Set(Setting value)

View File

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

View File

@@ -1,33 +0,0 @@
using System;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using Netch.Controllers;
using Netch.Interops;
using Netch.Utils;
namespace Netch.Models
{
public class TunAdapter : IAdapter
{
private const string ComponentIdWintun = "wintun";
public TunAdapter()
{
AdapterId = AdapterUtils.GetAdapterId(ComponentIdWintun) ?? throw new Exception("wintun adapter not found");
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.Id == AdapterId);
InterfaceIndex = NetworkInterface.GetIPProperties().GetIPv4Properties().Index;
Gateway = IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
Logging.Info($"WinTUN 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {InterfaceIndex}");
}
public string AdapterId { get; set; }
public int InterfaceIndex { get; }
public IPAddress Gateway { get; }
public NetworkInterface NetworkInterface { get; }
}
}

View File

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

21
Netch/NativeMethods.txt Normal file
View File

@@ -0,0 +1,21 @@
// IpHlpApi.dll
GetBestRoute
GetExtendedTcpTable
MIB_TCPTABLE_OWNER_PID
ADDRESS_FAMILY
// User32.dll
SetWindowPos
GetWindowLong
ShowWindow
WINDOW_STYLE
// Kernel32.dll
AllocConsole
GetConsoleWindow
// Ws2_32.dll
ntohs
// Windows.h
// WIN32_ERROR

View File

@@ -1,20 +1,35 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Windows.Win32;
using Windows.Win32.Foundation;
using Microsoft.VisualStudio.Threading;
using Netch.Controllers;
using Netch.Enums;
using Netch.Forms;
using Netch.Services;
using Netch.Utils;
using static Vanara.PInvoke.Kernel32;
using Serilog;
using Serilog.Events;
using SingleInstance;
#if RELEASE
using Windows.Win32.UI.WindowsAndMessaging;
#endif
namespace Netch
{
public static class Netch
{
public static readonly SingleInstance.SingleInstance SingleInstance = new($"Global\\{nameof(Netch)}");
public static readonly SingleInstanceService SingleInstance = new($"Global\\{nameof(Netch)}");
internal static HWND ConsoleHwnd { get; private set; }
/// <summary>
/// 应用程序的主入口点
@@ -22,13 +37,6 @@ namespace Netch
[STAThread]
public static void Main(string[] args)
{
#if DEBUG
AttachAllocConsole();
#else
if (args.Contains(Constants.Parameter.Console))
AttachAllocConsole();
#endif
if (args.Contains(Constants.Parameter.ForceUpdate))
Flags.AlwaysShowNewVersionFound = true;
@@ -36,18 +44,19 @@ namespace Netch
Directory.SetCurrentDirectory(Global.NetchDir);
var binPath = Path.Combine(Global.NetchDir, "bin");
Environment.SetEnvironmentVariable("PATH", $"{Environment.GetEnvironmentVariable("PATH")};{binPath}");
AddDllDirectory(binPath);
Updater.Updater.CleanOld(Global.NetchDir);
Updater.CleanOld(Global.NetchDir);
// 预创建目录
var directories = new[] {"mode\\Custom", "data", "i18n", "logging"};
var directories = new[] { "mode\\Custom", "data", "i18n", "logging" };
foreach (var item in directories)
if (!Directory.Exists(item))
Directory.CreateDirectory(item);
// 加载配置
Configuration.Load();
#pragma warning disable VSTHRD002
Configuration.LoadAsync().Wait();
#pragma warning restore VSTHRD002
if (!SingleInstance.IsFirstInstance)
{
@@ -57,7 +66,6 @@ namespace Netch
}
SingleInstance.ArgumentsReceived.Subscribe(SingleInstance_ArgumentsReceived);
SingleInstance.ListenForArgumentsFromSuccessiveInstances();
// 清理上一次的日志文件,防止淤积占用磁盘空间
if (Directory.Exists("logging"))
@@ -71,6 +79,10 @@ namespace Netch
dir.Delete(true);
}
InitConsole();
CreateLogger();
// 加载语言
i18N.Load(Global.Settings.Language);
@@ -80,12 +92,14 @@ namespace Netch
Environment.Exit(2);
}
Logging.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
Task.Run(() => { Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); });
Task.Run(LogEnvironment).Forget();
CheckClr();
CheckOS();
// 绑定错误捕获
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += Application_OnException;
Application.ApplicationExit += Application_OnExit;
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
@@ -93,16 +107,81 @@ namespace Netch
Application.Run(Global.MainForm);
}
private static void AttachAllocConsole()
private static void LogEnvironment()
{
if (!AttachConsole(ATTACH_PARENT_PROCESS))
AllocConsole();
Log.Information("Netch Version: {Version}", $"{UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
Log.Information("OS: {OSVersion}", Environment.OSVersion);
Log.Information("SHA256: {Hash}", $"{Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}");
Log.Information("System Language: {Language}", CultureInfo.CurrentCulture.Name);
if (Log.IsEnabled(LogEventLevel.Debug))
Log.Debug("Third-party Drivers:\n{Drivers}", string.Join("\n", SystemInfo.SystemDrivers(false)));
}
public static void Application_OnException(object sender, ThreadExceptionEventArgs e)
private static void CheckClr()
{
Logging.Error(e.Exception.ToString());
Utils.Utils.Open(Logging.LogFile);
var framework = Assembly.GetExecutingAssembly().GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
if (framework == null)
{
Log.Warning("TargetFrameworkAttribute null");
return;
}
var frameworkName = new FrameworkName(framework);
if (frameworkName.Version.Major != Environment.Version.Major)
{
Log.Information("CLR: {Version}", Environment.Version);
Flags.NoSupport = true;
if(!Global.Settings.NoSupportDialog)
MessageBoxX.Show(i18N.TranslateFormat("{0} won't get developers' support, Please do not report any issues or seek help from developers.", "CLR " + Environment.Version), LogLevel.WARNING);
}
}
private static void CheckOS()
{
if (Environment.OSVersion.Version.Build < 17763)
{
Flags.NoSupport = true;
if(!Global.Settings.NoSupportDialog)
MessageBoxX.Show(i18N.TranslateFormat("{0} won't get developers' support, Please do not report any issues or seek help from developers.", Environment.OSVersion), LogLevel.WARNING);
}
}
private static void InitConsole()
{
PInvoke.AllocConsole();
ConsoleHwnd = PInvoke.GetConsoleWindow();
#if RELEASE
PInvoke.ShowWindow(ConsoleHwnd, SHOW_WINDOW_CMD.SW_HIDE);
#endif
}
public static void CreateLogger()
{
Log.Logger = new LoggerConfiguration()
#if DEBUG
.MinimumLevel.Verbose()
.WriteTo.Async(c => c.Debug(outputTemplate: Constants.OutputTemplate))
#else
.MinimumLevel.Debug()
#endif
.WriteTo.Async(c => c.File(Path.Combine(Global.NetchDir, Constants.LogFile),
outputTemplate: Constants.OutputTemplate,
rollOnFileSizeLimit: false))
.MinimumLevel.Override(@"Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.CreateLogger();
}
private static void Application_OnException(object sender, ThreadExceptionEventArgs e)
{
Log.Error(e.Exception, "未处理异常");
}
private static void Application_OnExit(object? sender, EventArgs eventArgs)
{
Log.CloseAndFlush();
}
private static void SingleInstance_ArgumentsReceived(IEnumerable<string> args)

View File

@@ -1,19 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\common.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows7</TargetFramework>
<Configurations>Debug;Release</Configurations>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<StartupObject>Netch.Netch</StartupObject>
<ApplicationManifest>App.manifest</ApplicationManifest>
<ApplicationIcon>Resources\Netch.ico</ApplicationIcon>
<Platforms>x64</Platforms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<LangVersion>latest</LangVersion>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<ApplicationIcon>Resources\Netch.ico</ApplicationIcon>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<NoWarn>VSTHRD100</NoWarn>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<AnalysisMode>Default</AnalysisMode>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
@@ -22,95 +21,64 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<NoWarn />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NoWarn />
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<OutputPath>bin\x64\Release\</OutputPath>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<None Remove=".gitignore" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="HMBSbige.SingleInstance" Version="5.0.0" />
<PackageReference Include="HMBSbige.SingleInstance" Version="5.0.7" />
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.2.4089">
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.71" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="16.10.56" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.506-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.10.4539">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="4.1.2" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" Condition="'$(Configuration)'=='Debug'" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Stun.Net" Version="5.0.0" />
<PackageReference Include="System.Management" Version="5.0.0" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="TaskScheduler" Version="2.9.1" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.7" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.7" />
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
<PackageReference Include="WindowsFirewallHelper" Version="2.1.4.81" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Interop.nfapinet\Interop.nfapinet.csproj" />
</ItemGroup>
<ItemGroup>
<None Visible="false" Include="..\binaries\**" LinkBase="bin" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
<None Remove="..\binaries\.git" />
<None Visible="false" Include="..\translations\i18n\**" LinkBase="i18n" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
<None Visible="false" Include="..\modes\mode\**" LinkBase="mode" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Update="Forms\Mode\Route.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties />
</VisualStudio>
</ProjectExtensions>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="set TargetFramework=$(TargetFramework)&#xD;&#xA;set Configuration=$(Configuration)&#xD;&#xA;set ILMergeConsolePath=$(ILMergeConsolePath)&#xD;&#xA;set TargetDir=$(TargetDir)&#xD;&#xA;set SolutionDir=$(SolutionDir)&#xD;&#xA;call $(ProjectDir)PostBuild.bat" />
</Target>
<Target Condition="'$(PublishSingleFile)' == 'true'" AfterTargets="_ComputeFilesToBundle" Name="RemoveDupeAssemblies">
<ItemGroup>
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\build\native\x86\**" />
<!-- .NET 6 SDK fixes MSB4018 "Multiple entries with the same BundleRelativePath",
if still retain the following properties,
you will encounter a "lib/netstandard2.0/Dial2Lib.dll not found" error
-->
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\Dia2Lib.dll" />
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\OSExtensions.dll" />
<_FilesToBundle Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard1.6\TraceReloggerLib.dll" />
</ItemGroup>
</Target>
</Project>

View File

@@ -1,20 +0,0 @@
if %Configuration%==Release if %TargetFramework%==net48 (
:: Merge dlls
%ILMergeConsolePath% /wildcards /out:%TargetDir%Netch.exe ^
/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" ^
/targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8" ^
%TargetDir%Netch.exe ^
%TargetDir%*.dll
DEL /f %TargetDir%*.dll >NUL 2>&1
)
if %Configuration%==Release (
DEL /f %TargetDir%*.config >NUL 2>&1
DEL /f %TargetDir%*.pdb >NUL 2>&1
)
RD /s /Q %TargetDir%x86 >NUL 2>&1
RD /s /Q %TargetDir%de %TargetDir%es %TargetDir%fr %TargetDir%it %TargetDir%pl %TargetDir%ru %TargetDir%zh-CN >NUL 2>&1
exit 0

View File

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

View File

@@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Netch.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -15,8 +15,8 @@
"Stopping": "正在停止中",
"Stopped": "已停止",
"Starting {0}": "正在启动 {0}",
"Starting NatTester": "正在启动 NAT 测试",
"SetupBypass": "设置绕行规则",
"Testing NAT Type": "正在测试 NAT 类型",
"Setup Route Table Rule": "配置路由规则",
"Test failed": "测试失败",
"Starting update subscription": "正在更新订阅",
"Subscription updated": "订阅更新完毕",
@@ -48,9 +48,11 @@
"Transfer Protocol": "传输协议",
"Fake Type": "伪装类型",
"Host": "主机",
"Path": "路径",
"Path": "路径/服务名称",
"QUIC Security": "QUIC 加密方式",
"QUIC Secret": "QUIC 加密密钥",
"GRPC Mode": "QUIC 模式",
"GRPC ServiceName": "QUIC 服务名称",
"TLS Secure": "TLS 底层传输安全",
"Use Mux": "Mux 多路复用",
"Encrypt Method": "加密方式",
@@ -87,6 +89,7 @@
"Remove Netch Firewall Rules": "移除 Netch 防火墙规则",
"Open Directory": "打开目录",
"Show/Hide Console": "显示/隐藏控制台",
"About": "关于",
"FAQ": "常见问题",
@@ -100,6 +103,7 @@
"Please select a mode first": "请先选择一个模式",
"Please enter a profile name first": "请先为该配置设置一个名称",
"No saved profile here. Save a profile first by Ctrl+Click on the button": "当前按钮下没有保存配置,请先使用 CTRL + 左键 点击该按钮保存一个配置",
"Lookup Server hostname failed": "解析服务器主机名失败",
"Used": "已使用",
"Testing": "测试中",
@@ -147,18 +151,18 @@
"Check update when opened": "打开软件时检查更新",
"Check Beta update": "检查 Beta 更新",
"Update Servers when opened": "打开软件时更新服务器",
"Proxy Protocol": "代理协议",
"Filter Protocol": "Filter 协议",
"Handle process's DNS Hijack": "被代理进程 DNS 劫持",
"Global ICMP Hijack": "全局 ICMP 劫持",
"Child Process Handle": "子进程代理",
"ProfileCount": "快捷配置数量",
"Delay test after start": "启动后延迟测试",
"ServerPingType": "测速方式",
"ICMP Delay(ms)": "ICMP 延迟(毫秒)",
"Profile Count": "快捷配置数量",
"Delay test after start(sec)": "启动后延迟测试(秒)",
"Ping Protocol": "延迟测试协议",
"Detection Tick(sec)": "检测心跳(秒)",
"STUN Server": "STUN 服务器",
"Language": "语言",
"Resolve Server Hostname": "解析服务器主机名",
"FullCone Support (Required Server Xray-core v1.3.0+)": "FullCone 支持(需服务端 Xray-core v1.3.0+",
"Disable Support Warning": "停用支持警告",
"Profile": "配置名",
"Profiles": "配置",
@@ -168,5 +172,9 @@
"Exit": "退出",
"The {0} port is in use.": "{0} 端口已被占用",
"The {0} port is reserved by system.": "{0} 端口是系统保留端口"
"The {0} port is reserved by system.": "{0} 端口是系统保留端口",
"\"Core.bin\" is missing. Please check your Antivirus software": "找不到 \"Core.bin\" 文件!请检查你的杀毒软件。",
"{0} won't get developers' support, Please do not report any issues or seek help from developers.": "{0} 将不会得到开发者的支持,请不要报告任何问题或寻求开发人员的帮助。",
"No Support": "不受支持"
}

View File

@@ -1,78 +0,0 @@
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
namespace Netch.Servers.Shadowsocks
{
public class SSController : Guard, IServerController
{
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"listening at"};
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"Invalid config path", "usage", "plugin service exit unexpectedly"};
public override string Name { get; } = "Shadowsocks";
public ushort? Socks5LocalPort { get; set; }
public string? LocalAddress { get; set; }
public void Start(in Server s, in Mode mode)
{
var server = (Shadowsocks) s;
var command = new SSParameter
{
s = server.AutoResolveHostname(),
p = server.Port,
b = this.LocalAddress(),
l = this.Socks5LocalPort(),
m = server.EncryptMethod,
k = server.Password,
u = true,
plugin = server.Plugin,
plugin_opts = server.PluginOption
};
StartInstanceAuto(command.ToString());
}
[Verb]
private class SSParameter : ParameterBase
{
public string? s { get; set; }
public ushort? p { get; set; }
public string? b { get; set; }
public ushort? l { get; set; }
public string? m { get; set; }
public string? k { get; set; }
public bool u { get; set; }
[Full]
[Optional]
public string? plugin { get; set; }
[Full]
[Optional]
[RealName("plugin-opts")]
public string? plugin_opts { get; set; }
[Full]
[Quote]
[Optional]
public string? acl { get; set; }
}
public override void Stop()
{
StopInstance();
}
}
}

View File

@@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
namespace Netch.Servers
{
public class ShadowsocksController : Guard, IServerController
{
public ShadowsocksController() : base("Shadowsocks.exe")
{
}
protected override IEnumerable<string> StartedKeywords => new[] { "listening at" };
protected override IEnumerable<string> FailedKeywords => new[] { "Invalid config path", "usage", "plugin service exit unexpectedly" };
public override string Name => "Shadowsocks";
public ushort? Socks5LocalPort { get; set; }
public string? LocalAddress { get; set; }
public async Task<Socks5LocalServer> StartAsync(Server s)
{
var server = (ShadowsocksServer)s;
var arguments = new object?[]
{
"-s", await server.AutoResolveHostnameAsync(),
"-p", server.Port,
"-b", this.LocalAddress(),
"-l", this.Socks5LocalPort(),
"-m", server.EncryptMethod,
"-k", server.Password,
"-u", SpecialArgument.Flag,
"--plugin", server.Plugin,
"--plugin-opts", server.PluginOption
};
await StartGuardAsync(Arguments.Format(arguments));
return new Socks5LocalServer(IPAddress.Loopback.ToString(), this.Socks5LocalPort(), server.Hostname);
}
}
}

View File

@@ -1,13 +1,13 @@
using Netch.Forms;
using Netch.Utils;
namespace Netch.Servers.Shadowsocks.Form
namespace Netch.Servers
{
public class ShadowsocksForm : ServerForm
{
public ShadowsocksForm(Shadowsocks? server = default)
public ShadowsocksForm(ShadowsocksServer? server = default)
{
server ??= new Shadowsocks();
server ??= new ShadowsocksServer();
Server = server;
CreateTextBox("Password", "Password", s => !s.IsNullOrWhiteSpace(), s => server.Password = s, server.Password);
CreateComboBox("EncryptMethod", "Encrypt Method", SSGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);

View File

@@ -1,11 +1,15 @@
using System.Collections.Generic;
using Netch.Models;
namespace Netch.Servers.Shadowsocks
namespace Netch.Servers
{
public class Shadowsocks : Server
public class ShadowsocksServer : Server
{
public override string Type { get; } = "SS";
public override string MaskedData()
{
return $"{EncryptMethod} + {Plugin}";
}
/// <summary>
/// 加密方式

View File

@@ -4,15 +4,14 @@ using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;
using Netch.Controllers;
using Netch.Interfaces;
using Netch.Models;
using Netch.Servers.Shadowsocks.Form;
using Netch.Servers.Shadowsocks.Models.SSD;
using Netch.Utils;
using Serilog;
namespace Netch.Servers.Shadowsocks
namespace Netch.Servers
{
public class SSUtil : IServerUtil
public class ShadowsocksUtil : IServerUtil
{
public ushort Priority { get; } = 1;
@@ -22,13 +21,13 @@ namespace Netch.Servers.Shadowsocks
public string ShortName { get; } = "SS";
public string[] UriScheme { get; } = {"ss", "ssd"};
public string[] UriScheme { get; } = { "ss", "ssd" };
public Type ServerType { get; } = typeof(Shadowsocks);
public Type ServerType { get; } = typeof(ShadowsocksServer);
public void Edit(Server s)
{
new ShadowsocksForm((Shadowsocks) s).ShowDialog();
new ShadowsocksForm((ShadowsocksServer)s).ShowDialog();
}
public void Create()
@@ -38,7 +37,7 @@ namespace Netch.Servers.Shadowsocks
public string GetShareLink(Server s)
{
var server = (Shadowsocks) s;
var server = (ShadowsocksServer)s;
// ss://method:password@server:port#Remark
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" +
HttpUtility.UrlEncode(server.Remark);
@@ -46,13 +45,13 @@ namespace Netch.Servers.Shadowsocks
public IServerController GetController()
{
return new SSController();
return new ShadowsocksController();
}
public IEnumerable<Server> ParseUri(string text)
{
if (text.StartsWith("ss://"))
return new[] {ParseSsUri(text)};
return new[] { ParseSsUri(text) };
if (text.StartsWith("ssd://"))
return ParseSsdUri(text);
@@ -62,13 +61,11 @@ namespace Netch.Servers.Shadowsocks
public bool CheckServer(Server s)
{
var server = (Shadowsocks) s;
var server = (ShadowsocksServer)s;
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
{
Logging.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
{
return false;
}
Log.Warning("不支持的 SS 加密方式:{Method}", server.EncryptMethod);
return false;
}
return true;
@@ -76,9 +73,9 @@ namespace Netch.Servers.Shadowsocks
public IEnumerable<Server> ParseSsdUri(string s)
{
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
var json = JsonSerializer.Deserialize<SSDJObject>(ShareLink.URLSafeBase64Decode(s.Substring(6)))!;
return json.servers.Select(server => new Shadowsocks
return json.servers.Select(server => new ShadowsocksServer
{
Remark = server.remarks,
Hostname = server.server,
@@ -93,9 +90,9 @@ namespace Netch.Servers.Shadowsocks
.Where(CheckServer);
}
public Shadowsocks ParseSsUri(string text)
public ShadowsocksServer ParseSsUri(string text)
{
var data = new Shadowsocks();
var data = new ShadowsocksServer();
text = text.Replace("/?", "?");
if (text.Contains("#"))

View File

@@ -1,9 +1,9 @@
#nullable disable
using System.Collections.Generic;
namespace Netch.Servers.Shadowsocks.Models.SSD
namespace Netch.Servers
{
public class Main
public class SSDJObject
{
/// <summary>
/// 机场名
@@ -38,6 +38,6 @@ namespace Netch.Servers.Shadowsocks.Models.SSD
/// <summary>
/// 服务器数组
/// </summary>
public List<SSDServer> servers;
public List<SSDServerJObject> servers;
}
}

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