Compare commits

..

305 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
ChsBuffer
5522245ce0 bump version to 1.8.3-Beta5 2021-03-28 02:47:19 +08:00
ChsBuffer
f518fd6867 Update binaries(Fix DNS) 2021-03-28 02:23:01 +08:00
ChsBuffer
e0120e7de0 Update SettingForm 2021-03-28 02:21:44 +08:00
ChsBuffer
3565251b4d Update Redirector
extract RedirectorConfig
move BypassIPs to Setting.TUNTAP
2021-03-28 02:13:03 +08:00
ChsBuffer
4a50ebd421 Update zh-cn 2021-03-28 02:13:03 +08:00
Connection Refused
4e03793ceb Update submodules 2021-03-28 02:05:24 +08:00
ChsBuffer
23399b872d Remove TUN HijackDNS value check 2021-03-28 00:56:59 +08:00
ChsBuffer
b553ddbb71 Refactor: Create Netch.Interops namespace 2021-03-28 00:54:04 +08:00
ChsBuffer
090e487733 Move MessageException Namespace and Optimize import 2021-03-28 00:51:42 +08:00
ChsBuffer
cada4c997e Update Release workflow 2021-03-28 00:13:49 +08:00
ChsBuffer
8746125dda Create Publish.ps1 2021-03-28 00:01:59 +08:00
ChsBuffer
d09b5adc33 Drop proxy client routing 2021-03-27 23:44:25 +08:00
ChsBuffer
54c1fb5578 remove unused aiodns protocol setting 2021-03-27 23:20:56 +08:00
ChsBuffer
f07413c882 Fix LogForm RouteForm Scale 2021-03-27 23:15:25 +08:00
ChsBuffer
5b2b6c9f96 Update DNSController and TUNController 2021-03-27 23:09:33 +08:00
ChsBuffer
4c4ad72d1d Update Setting 2021-03-27 22:55:18 +08:00
Connection Refused
830f3b3b60 Update modes 2021-03-27 22:33:20 +08:00
Connection Refused
777657e810 Update modes 2021-03-27 22:27:58 +08:00
Connection Refused
2413aabb15 Update aiodns to v1.0.3 2021-03-27 22:16:26 +08:00
Connection Refused
6ccb99d1d8 Update tun2socks 2021-03-27 22:10:23 +08:00
Connection Refused
ac0266a478 Update tun2socks 2021-03-27 21:51:30 +08:00
ChsBuffer
d701a8c950 Fix Create Process Mode validation typo
Update NFController
2021-03-27 19:41:16 +08:00
ChsBuffer
934443556c extract RedirectorInterop
Update TUNController
2021-03-27 19:29:42 +08:00
ChsBuffer
a69252819c Update Readme 2021-03-27 18:36:40 +08:00
ChsBuffer
f90773aa84 Update StringExtension Split 2021-03-27 18:27:09 +08:00
ChsBuffer
246f52e54e cleanup Reference 2021-03-27 18:24:13 +08:00
ChsBuffer
a5f6b4a2c0 Fix BUILD.ps1 2021-03-27 18:09:00 +08:00
ChsBuffer
66d7cededd Fix LogForm RouteForm ScaleDimensions 2021-03-27 17:59:13 +08:00
ChsBuffer
8254482799 Remove SearchComboBox 2021-03-27 17:56:34 +08:00
ChsBuffer
b215b2caa8 Fix TUNNetmaskTextBox Visible 2021-03-27 17:45:50 +08:00
ChsBuffer
5f9dbb0994 Update BUILD.ps1, Remove CLEAN.ps1 2021-03-27 17:44:47 +08:00
ChsBuffer
3cbd5af9a3 Extract TagItem class, Update Nullable 2021-03-27 17:40:18 +08:00
ChsBuffer
2ab693facf Update TFM to net5.0-windows7 2021-03-27 16:26:18 +08:00
ChsBuffer
664b1a7e6c Update TUNController 2021-03-27 16:24:15 +08:00
Connection Refused
ad1575b3c7 Update modes 2021-03-27 16:00:35 +08:00
Connection Refused
62b78d1b1d Update submodules 2021-03-27 15:56:04 +08:00
ChsBuffer
dd3ce126e3 Update TUNController (tun2socks.bin) 2021-03-27 03:06:54 +08:00
ChsBuffer
a295cf6250 Update Append bin to PATH 2021-03-27 03:05:45 +08:00
ChsBuffer
a507df5f30 Debug Level Log 2021-03-27 03:05:32 +08:00
ChsBuffer
0a7b405f1b Revert "Update Netch.csproj"
This reverts commit 5fc7c460aa.
2021-03-26 23:40:33 +08:00
Connection Refused
c61da9b918 Update modes 2021-03-26 19:39:54 +08:00
Connection Refused
9bf3490cf9 Update TUNController 2021-03-26 19:32:57 +08:00
Connection Refused
c505e2abbb Update TUNController 2021-03-26 19:31:42 +08:00
Connection Refused
5fc7c460aa Update Netch.csproj 2021-03-26 19:31:28 +08:00
Connection Refused
c79f62334c Update aiodns.conf 2021-03-26 19:18:31 +08:00
Connection Refused
2dc4308427 Update aiodns.conf 2021-03-26 19:18:09 +08:00
Connection Refused
c3c534eb92 Update binaries 2021-03-26 19:14:14 +08:00
Connection Refused
dbef41d8a4 Update README.md 2021-03-26 18:40:32 +08:00
ChsBuffer
e3d6a62e81 Update RouteHelper usage 2021-03-26 18:35:46 +08:00
ChsBuffer
415c7705ac cleanup drop http support 2021-03-26 18:35:12 +08:00
Connection Refused
4ab844e31c Update NativeMethods 2021-03-26 18:25:08 +08:00
ChsBuffer
f4759d2f94 Drop HTTPController(Drop WebProxy, Update server with proxy etc.) 2021-03-26 18:17:58 +08:00
ChsBuffer
a080de6ca4 replace eycorsican/go-tun2socks with aiocloud/tun2socks(WinTUN) 2021-03-26 17:56:28 +08:00
Connection Refused
f8148cb730 Merge pull request #598 from NetchX/dependabot/submodules/modes-1471298
Bump modes from `72ad96d` to `1471298`
2021-03-26 17:04:27 +08:00
dependabot[bot]
b092b6a4d4 Bump modes from 72ad96d to 1471298
Bumps [modes](https://github.com/NetchX/NetchMode) from `72ad96d` to `1471298`.
- [Release notes](https://github.com/NetchX/NetchMode/releases)
- [Commits](72ad96d018...1471298210)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-26 09:04:07 +00:00
199 changed files with 4888 additions and 7174 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: .\BUILD.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\x64\Release\
7z rn C:\builtfiles\Netch.7z Release Netch
echo "Netch_SHA256=$(.\GetSHA256.ps1 C:\builtfiles\Netch.7z)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "Netch_EXE_SHA256=$(.\GetSHA256.ps1 Netch\bin\x64\Release\Netch.exe)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
.\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,12 +0,0 @@
Write-Host 'Building'
msbuild -v:n /p:Configuration="Release" `
/p:Platform="x64" `
/p:TargetFramework=net48 `
/p:SolutionDir="$pwd\" `
/restore `
Netch\Netch.csproj
if ($LASTEXITCODE) { exit $LASTEXITCODE }
Write-Host 'Build done'

View File

@@ -1,21 +0,0 @@
if (Test-Path Netch\bin)
{
Remove-Item -Recurse -Force Netch\bin
}
if (Test-Path Netch\obj)
{
Remove-Item -Recurse -Force Netch\obj
}
if (Test-Path NetchLib\bin)
{
Remove-Item -Recurse -Force NetchLib\bin
}
if (Test-Path NetchLib\obj)
{
Remove-Item -Recurse -Force NetchLib\obj
}
exit 0

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,9 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<LangVersion>latest</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +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}") = "SearchComboBox", "SearchComboBox\SearchComboBox.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
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
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Debug|x64.ActiveCfg = Debug|Any CPU
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Debug|x64.Build.0 = Debug|Any CPU
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Release|x64.ActiveCfg = Release|Any CPU
{A8715AF4-ACC6-43F9-9381-4294C5360623}.Release|x64.Build.0 = Release|Any CPU
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|x64
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|x64
{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

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
</configuration>

View File

@@ -2,15 +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 UserACL = "data\\user.acl";
public const string BuiltinACL = "bin\\default.acl";
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,57 +1,35 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
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()
{
aiodns_free();
await FreeAsync();
}
/// <summary>
/// 启动DNS服务
/// </summary>
/// <returns></returns>
public void Start()
public async Task StartAsync()
{
aiodns_dial((int) NameList.TYPE_REST, null);
aiodns_dial((int) NameList.TYPE_ADDR, Encoding.UTF8.GetBytes($"{Global.Settings.LocalAddress}:53"));
aiodns_dial((int) NameList.TYPE_LIST, Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)));
aiodns_dial((int) NameList.TYPE_CDNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"));
aiodns_dial((int) NameList.TYPE_ODNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"));
aiodns_dial((int) NameList.TYPE_METH, Encoding.UTF8.GetBytes(Global.Settings.AioDNS.Protocol));
MainController.PortCheck(Global.Settings.AioDNS.ListenPort, "DNS");
if (!aiodns_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.");
}
#region NativeMethods
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aiodns_dial(int name, byte[]? value);
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aiodns_init();
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern void aiodns_free();
private enum NameList
{
TYPE_REST,
TYPE_ADDR,
TYPE_LIST,
TYPE_CDNS,
TYPE_ODNS,
TYPE_METH
}
#endregion
}
}

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,93 +0,0 @@
using System.Threading.Tasks;
using WindowsProxy;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Servers.Trojan;
using Netch.Utils;
using Netch.Utils.HttpProxyHandler;
namespace Netch.Controllers
{
public class HTTPController : IModeController
{
public readonly PrivoxyController PrivoxyController = new();
private ProxyStatus? _oldState;
public string Name { get; } = "HTTP";
/// <summary>
/// 启动
/// </summary>
/// <param name="mode">模式</param>
/// <returns>是否启动成功</returns>
public void Start(in Mode mode)
{
PrivoxyController.Start(MainController.Server!);
string? pacUrl = null;
if (MainController.Server is Socks5 or Trojan && mode.BypassChina || (Global.Settings.AlwaysStartPACServer ?? false))
{
try
{
PortHelper.CheckPort(Global.Settings.Pac_Port);
}
catch
{
Global.Settings.Pac_Port = PortHelper.GetAvailablePort();
}
pacUrl = PACServerHandle.InitPACServer();
}
if (mode.Type is 3)
{
using var service = new ProxyService();
_oldState = service.Query();
if (pacUrl != null)
{
service.AutoConfigUrl = pacUrl;
service.Pac();
}
else
{
service.Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}";
service.Bypass = string.Join(";", ProxyService.LanIp);
service.Global();
}
}
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
var tasks = new[]
{
Task.Run(PrivoxyController.Stop),
Task.Run(() =>
{
PACServerHandle.Stop();
if (_oldState != null)
{
using var service = new ProxyService();
if (_oldState.IsProxy && _oldState.ProxyServer == service.Query().ProxyServer ||
_oldState.IsAutoProxyUrl && _oldState.AutoConfigUrl!.StartsWith(PACServerHandle.PacPrefix))
{
service.Direct();
return;
}
service.Set(_oldState);
}
})
};
Task.WaitAll(tasks);
}
}
}

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,89 +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;
if (server is Socks5 && mode.Type == 4)
throw new MessageException("Already Socks5 Server");
await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules));
// 刷新DNS缓存
NativeMethods.FlushDNSResolverCache();
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)
{
@@ -93,84 +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 (ModeController == null)
return;
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)
@@ -193,16 +161,9 @@ namespace Netch.Controllers
{
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
{
string fileName;
try
{
fileName = p.MainModule!.FileName;
}
catch (Exception e)
{
Logging.Warning(e.ToString());
var fileName = p.MainModule?.FileName;
if (fileName == null)
continue;
}
if (fileName.StartsWith(Global.NetchDir))
{
@@ -217,16 +178,30 @@ namespace Netch.Controllers
PortCheck(port, portName, PortType.TCP);
}
}
public class MessageException : Exception
{
public MessageException()
public static async Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
{
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
}
public MessageException(string message) : base(message)
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,54 +1,64 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
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 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();
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
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
aio_dial((int) NameList.TYPE_FILTERUDP, (Global.Settings.ProcessProxyProtocol != PortType.TCP).ToString().ToLower());
aio_dial((int) NameList.TYPE_FILTERTCP, (Global.Settings.ProcessProxyProtocol != PortType.UDP).ToString().ToLower());
dial_Server(Global.Settings.ProcessProxyProtocol);
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
aio_dial((int) NameList.TYPE_REDIRCTOR_DNS, Global.Settings.RedirectDNS ? Global.Settings.RedirectDNSAddr : "");
aio_dial((int) NameList.TYPE_REDIRCTOR_ICMP, Global.Settings.RedirectICMP ? Global.Settings.RedirectICMPAddr : "");
aio_dial((int) NameList.TYPE_FILTERCHILDPROC, Global.Settings.ChildProcessHandle.ToString().ToLower());
Dial(NameList.TYPE_DNSHOST, _rdrConfig.DNSHijack ? _rdrConfig.DNSHijackHost : "");
if (!aio_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()
{
aio_free();
await FreeAsync();
}
#region CheckRule
@@ -63,14 +73,14 @@ namespace Netch.Controllers
try
{
if (r.StartsWith("!"))
return aio_dial((int) NameList.TYPE_ADDNAME, r.Substring(1));
return Dial(NameList.TYPE_ADDNAME, r.Substring(1));
return aio_dial((int) NameList.TYPE_ADDNAME, r);
return Dial(NameList.TYPE_ADDNAME, r);
}
finally
{
if (clear)
aio_dial((int) NameList.TYPE_CLRNAME, "");
Dial(NameList.TYPE_CLRNAME, "");
}
}
@@ -82,7 +92,7 @@ namespace Netch.Controllers
public static bool CheckRules(IEnumerable<string> rules, out IEnumerable<string> results)
{
results = rules.Where(r => !CheckCppRegex(r, false));
aio_dial((int) NameList.TYPE_CLRNAME, "");
Dial(NameList.TYPE_CLRNAME, "");
return !results.Any();
}
@@ -93,91 +103,71 @@ 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)
if (server is Socks5Server socks5)
{
offset = UdpNameListOffset;
server = MainController.UdpServer!;
controller = MainController.UdpServerController!;
Dial(NameList.TYPE_TCPTYPE + offset, "Socks5");
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
{
offset = 0;
server = MainController.Server!;
controller = MainController.ServerController!;
}
if (server is Socks5 socks5)
{
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
aio_dial((int) NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
aio_dial((int) NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
}
else if (server is Shadowsocks shadowsocks && !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS)
{
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
aio_dial((int) NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod);
aio_dial((int) NameList.TYPE_TCPPASS + offset, shadowsocks.Password);
}
else
{
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"127.0.0.1:{controller.Socks5LocalPort()}");
aio_dial((int) NameList.TYPE_TCPUSER + offset, string.Empty);
aio_dial((int) NameList.TYPE_TCPPASS + offset, string.Empty);
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
Trace.Assert(false);
}
}
private void dial_Name(Mode mode)
{
aio_dial((int) NameList.TYPE_CLRNAME, "");
var list = new List<string>();
foreach (var s in mode.FullRule)
Dial(NameList.TYPE_CLRNAME, "");
var invalidList = new List<string>();
foreach (var s in mode.GetRules())
{
if (s.StartsWith("!"))
{
if (!aio_dial((int) NameList.TYPE_BYPNAME, s.Substring(1)))
list.Add(s);
if (!Dial(NameList.TYPE_BYPNAME, s.Substring(1)))
invalidList.Add(s);
continue;
}
if (!aio_dial((int) NameList.TYPE_ADDNAME, s))
list.Add(s);
if (!Dial(NameList.TYPE_ADDNAME, s))
invalidList.Add(s);
}
if (list.Any())
throw new MessageException(GenerateInvalidRulesMessage(list));
if (invalidList.Any())
throw new MessageException(GenerateInvalidRulesMessage(invalidList));
aio_dial((int) NameList.TYPE_ADDNAME, @"NTT\.exe");
aio_dial((int) NameList.TYPE_BYPNAME, "^" + Global.NetchDir.ToRegexString() + @"((?!NTT\.exe).)*$");
Dial(NameList.TYPE_ADDNAME, @"NTT\.exe");
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))
{
@@ -207,7 +197,7 @@ namespace Netch.Controllers
if (!reinstall)
return;
Logging.Info("更新驱动");
Log.Information("更新驱动");
UninstallDriver();
InstallDriver();
}
@@ -216,20 +206,20 @@ namespace Netch.Controllers
/// 安装 NF 驱动
/// </summary>
/// <returns>驱动是否安装成功</returns>
public static void InstallDriver()
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}");
}
@@ -238,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}");
}
}
@@ -253,7 +243,7 @@ namespace Netch.Controllers
/// <returns>是否成功卸载</returns>
public static bool UninstallDriver()
{
Logging.Info("卸载 NF 驱动");
Log.Information("卸载 NF 驱动");
try
{
if (NFService.Status == ServiceControllerStatus.Running)
@@ -277,61 +267,5 @@ namespace Netch.Controllers
}
#endregion
#region NativeMethods
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
private static extern bool aio_init();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
private static extern bool aio_free();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
private static extern ulong aio_getUP();
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
private static extern ulong aio_getDL();
public enum NameList
{
//bool
TYPE_FILTERLOOPBACK,
TYPE_FILTERTCP,
TYPE_FILTERUDP,
TYPE_FILTERIP,
TYPE_FILTERCHILDPROC, //子进程捕获
TYPE_TCPLISN,
TYPE_TCPTYPE,
TYPE_TCPHOST,
TYPE_TCPUSER,
TYPE_TCPPASS,
TYPE_TCPMETH,
TYPE_UDPTYPE,
TYPE_UDPHOST,
TYPE_UDPUSER,
TYPE_UDPPASS,
TYPE_UDPMETH,
TYPE_ADDNAME,
TYPE_ADDFIP,
TYPE_BYPNAME,
TYPE_CLRNAME,
TYPE_CLRFIP,
//str addr x.x.x.x only ipv4
TYPE_REDIRCTOR_DNS,
TYPE_REDIRCTOR_ICMP
}
#endregion
}
}

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,45 +0,0 @@
using System.IO;
using System.Text;
using Netch.Models;
using Netch.Servers.Socks5;
namespace Netch.Controllers
{
public class PrivoxyController : Guard, IController
{
public PrivoxyController()
{
RedirectStd = false;
}
public override string MainFile { get; protected set; } = "Privoxy.exe";
public override string Name { get; } = "Privoxy";
public override void Stop()
{
StopInstance();
}
public void Start(Server server)
{
var text = new StringBuilder(File.ReadAllText("bin\\default.conf"));
text.Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString());
text.Replace("0.0.0.0", Global.Settings.LocalAddress); /* BIND_HOST */
if (server is Socks5 socks5 && !socks5.Auth())
{
text.Replace("/ 127.0.0.1", $"/ {server.AutoResolveHostname()}"); /* DEST_HOST */
text.Replace("_DEST_PORT_", socks5.Port.ToString());
}
text.Replace("_DEST_PORT_", Global.Settings.Socks5LocalPort.ToString());
File.WriteAllText("data\\privoxy.conf", text.ToString());
StartInstanceAuto("..\\data\\privoxy.conf");
}
}
}

View File

@@ -0,0 +1,210 @@
using System;
using System.Diagnostics;
using System.IO;
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;
using Netch.Utils;
using Serilog;
using static Netch.Interops.tun2socks;
namespace Netch.Controllers
{
public class TUNController : IModeController
{
private const string DummyDns = "6.6.6.6";
private readonly DNSController _aioDnsController = new();
private Mode _mode = null!;
private IPAddress? _serverRemoteAddress;
private TUNConfig _tunConfig = null!;
private NetRoute _tun;
private NetRoute _outbound;
public string Name => "tun2socks";
public async Task StartAsync(Socks5Server server, Mode mode)
{
_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, _outbound.Gateway);
Dial(NameList.TYPE_BYPLIST, "disabled");
#region Server
Dial(NameList.TYPE_TCPREST, "");
Dial(NameList.TYPE_TCPTYPE, "Socks5");
Dial(NameList.TYPE_UDPREST, "");
Dial(NameList.TYPE_UDPTYPE, "Socks5");
if (server is Socks5Server socks5)
{
Dial(NameList.TYPE_TCPHOST, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
Dial(NameList.TYPE_UDPHOST, $"{await socks5.AutoResolveHostnameAsync()}:{socks5.Port}");
if (socks5.Auth())
{
Dial(NameList.TYPE_TCPUSER, socks5.Username!);
Dial(NameList.TYPE_TCPPASS, socks5.Password!);
Dial(NameList.TYPE_UDPUSER, socks5.Username!);
Dial(NameList.TYPE_UDPPASS, socks5.Password!);
}
}
else
{
Trace.Assert(false);
}
#endregion
#region DNS
if (_tunConfig.UseCustomDNS)
{
Dial(NameList.TYPE_DNSADDR, _tunConfig.HijackDNS);
}
else
{
await _aioDnsController.StartAsync();
Dial(NameList.TYPE_DNSADDR, $"127.0.0.1:{Global.Settings.AioDNS.ListenPort}");
}
#endregion
if (!Init())
throw new MessageException("tun2socks start failed.");
var tunIndex = (int)RouteHelper.ConvertLuidToIndex(tun_luid());
_tun = NetRoute.TemplateBuilder(_tunConfig.Gateway, tunIndex);
RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork,
_tunConfig.Address,
(byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask),
(ulong)tunIndex);
SetupRouteTable();
}
public async Task StopAsync()
{
var tasks = new[]
{
FreeAsync(),
Task.Run(ClearRouteTable),
_aioDnsController.StopAsync()
};
await Task.WhenAll(tasks);
}
private void CheckDriver()
{
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
{
Log.Information("Copy wintun.dll to System Directory");
File.Copy(binDriver, sysDriver, true);
}
catch (Exception e)
{
Log.Error(e, "复制 wintun.dll 异常");
throw new MessageException($"Failed to copy wintun.dll to system directory: {e.Message}");
}
}
#region Route
private void SetupRouteTable()
{
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)
{
case ModeType.ProxyRuleIPs:
// rules
RouteUtils.CreateRouteFill(_tun, _mode.GetRules());
if (_tunConfig.ProxyDNS)
{
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 ModeType.BypassRuleIPs:
RouteUtils.CreateRouteFill(_outbound, _mode.GetRules());
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;
}
}
private void ClearRouteTable()
{
if (_serverRemoteAddress != null)
RouteUtils.DeleteRoute(_outbound.FillTemplate(_serverRemoteAddress.ToString(), 32));
RouteUtils.DeleteRouteFill(_outbound, Global.Settings.TUNTAP.BypassIPs);
switch (_mode.Type)
{
case ModeType.BypassRuleIPs:
RouteUtils.DeleteRouteFill(_outbound, _mode.GetRules());
NetworkInterfaceUtils.SetInterfaceMetric(_outbound.InterfaceIndex);
break;
}
}
#endregion
}
}

View File

@@ -1,290 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
namespace Netch.Controllers
{
public class TUNTAPController : Guard, IModeController
{
private readonly List<string> _directIPs = new();
private readonly List<string> _proxyIPs = new();
/// <summary>
/// 服务器 IP 地址
/// </summary>
private IPAddress _serverAddresses = null!;
/// <summary>
/// 本地 DNS 服务控制器
/// </summary>
public DNSController DNSController = new();
protected override IEnumerable<string> StartedKeywords { get; set; } = new[] {"Running"};
protected override IEnumerable<string> StoppedKeywords { get; set; } = new[] {"failed", "invalid vconfig file"};
public override string MainFile { get; protected set; } = "tun2socks.exe";
protected override Encoding InstanceOutputEncoding { get; } = Encoding.UTF8;
public override string Name { get; } = "tun2socks";
private readonly OutboundAdapter _outbound = new();
private TapAdapter _tap = null!;
public void Start(in Mode mode)
{
var server = MainController.Server!;
_serverAddresses = DnsUtils.Lookup(server.Hostname)!; // server address have been cached when MainController.Start
if (TUNTAP.GetComponentID() == null)
TUNTAP.AddTap();
_tap = new TapAdapter();
List<string> dns;
if (Global.Settings.TUNTAP.UseCustomDNS)
{
dns = Global.Settings.TUNTAP.DNS.Any() ? Global.Settings.TUNTAP.DNS : Global.Settings.TUNTAP.DNS = new List<string> {"1.1.1.1"};
}
else
{
MainController.PortCheck(53, "DNS");
DNSController.Start();
dns = new List<string> {"127.0.0.1"};
}
var parameter = new Tun2SocksParameter
{
tunAddr = Global.Settings.TUNTAP.Address,
tunMask = Global.Settings.TUNTAP.Netmask,
tunGw = Global.Settings.TUNTAP.Gateway,
tunDns = DnsUtils.Join(dns),
tunName = TUNTAP.GetName(_tap.ComponentID),
fakeDns = Global.Settings.TUNTAP.UseFakeDNS && Flags.SupportFakeDns
};
if (server is Socks5 socks5 && !socks5.Auth())
parameter.proxyServer = $"{server.AutoResolveHostname()}:{server.Port}";
else
parameter.proxyServer = $"127.0.0.1:{Global.Settings.Socks5LocalPort}";
StartInstanceAuto(parameter.ToString(), ProcessPriorityClass.RealTime);
SetupRouteTable(mode);
}
[Verb]
public class Tun2SocksParameter : ParameterBase
{
public string proxyServer { get; set; }
public string tunAddr { get; set; }
public string tunMask { get; set; }
public string tunGw { get; set; }
public string tunDns { get; set; }
public string tunName { get; set; }
public bool fakeDns { get; set; }
}
/// <summary>
/// TUN/TAP停止
/// </summary>
public override void Stop()
{
var tasks = new[]
{
Task.Run(StopInstance),
Task.Run(ClearRouteTable),
Task.Run(DNSController.Stop)
};
Task.WaitAll(tasks);
}
/// <summary>
/// 设置绕行规则
/// </summary>
/// <returns>是否设置成功</returns>
private void SetupRouteTable(Mode mode)
{
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
Logging.Info("设置路由规则");
#region Rule IPs
switch (mode.Type)
{
case 1:
// 代理规则 IP
Logging.Info("代理 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
if (Global.Settings.TUNTAP.ProxyDNS)
{
Logging.Info("代理 → 自定义 DNS");
if (Global.Settings.TUNTAP.UseCustomDNS)
RouteAction(Action.Create, Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
else
RouteAction(Action.Create, $"{Global.Settings.AioDNS.OtherDNS}/32", RouteType.TUNTAP);
}
break;
case 2:
// 绕过规则 IP
// 将 TUN/TAP 网卡权重放到最高
SetInterface(RouteType.TUNTAP, 0);
Logging.Info("绕行 → 规则 IP");
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
break;
}
#endregion
Logging.Info("绕行 → 服务器 IP");
if (!IPAddress.IsLoopback(_serverAddresses))
RouteAction(Action.Create, $"{_serverAddresses}/32", RouteType.Outbound);
Logging.Info("绕行 → 全局绕过 IP");
RouteAction(Action.Create, Global.Settings.BypassIPs, RouteType.Outbound);
if (mode.Type == 2)
{
Logging.Info("代理 → 全局");
RouteAction(Action.Create, "0.0.0.0/0", RouteType.TUNTAP);
}
}
private void SetInterface(RouteType routeType, int? metric = null)
{
IAdapter adapter = routeType switch
{
RouteType.Outbound => _outbound,
RouteType.TUNTAP => _tap,
_ => throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null)
};
var arguments = $"interface ip set interface {adapter.Index} ";
if (metric != null)
arguments += $"metric={metric} ";
Process.Start(new ProcessStartInfo
{
FileName = "netsh",
Arguments = arguments,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
CreateNoWindow = true
});
}
/// <summary>
/// 清除绕行规则
/// </summary>
private bool ClearRouteTable()
{
RouteAction(Action.Delete, _directIPs, RouteType.Outbound);
RouteAction(Action.Delete, _proxyIPs, RouteType.TUNTAP);
_directIPs.Clear();
_proxyIPs.Clear();
return true;
}
public bool TestFakeDNS()
{
try
{
InitInstance("-h");
Instance!.Start();
return Instance.StandardError.ReadToEnd().Contains("-fakeDns");
}
catch
{
return false;
}
}
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0)
{
foreach (var address in ipNetworks)
RouteAction(action, address, routeType, metric);
}
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0)
{
var s = ipNetwork.Split('/');
if (s.Length != 2)
{
Logging.Warning($"Failed to parse rule {ipNetwork}");
return false;
}
IAdapter adapter;
List<string> ipList;
switch (routeType)
{
case RouteType.TUNTAP:
adapter = _tap;
ipList = _proxyIPs;
break;
case RouteType.Outbound:
adapter = _outbound;
ipList = _directIPs;
break;
default:
throw new ArgumentOutOfRangeException(nameof(routeType), routeType, null);
}
string network = s[0];
var cidr = ushort.Parse(s[1]);
string gateway = adapter.Gateway.ToString();
var index = adapter.Index;
bool result;
switch (action)
{
case Action.Create:
result = NativeMethods.CreateRoute(network, cidr, gateway, index, metric);
ipList.Add(ipNetwork);
break;
case Action.Delete:
result = NativeMethods.DeleteRoute(network, cidr, gateway, index, metric);
break;
default:
throw new ArgumentOutOfRangeException(nameof(action), action, null);
}
if (!result)
Logging.Warning($"Failed to {action} Route on {routeType} Adapter: {ipNetwork} metric {metric}");
return result;
}
private enum RouteType
{
Outbound,
TUNTAP
}
private enum Action
{
Create,
Delete
}
}
}

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 = @"Beta4";
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,4 +1,4 @@
namespace Netch.Models
namespace Netch.Enums
{
public enum LogLevel
{

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

@@ -1,5 +1,4 @@
using System;
using Netch.Controllers;
namespace Netch
{
@@ -7,10 +6,8 @@ namespace Netch
{
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
private static readonly Lazy<bool> LazySupportFakeDns = new(() => new TUNTAPController().TestFakeDNS());
public static bool SupportFakeDns => LazySupportFakeDns.Value;
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,8 +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
{
@@ -18,7 +19,7 @@ namespace Netch.Forms
{
i18N.TranslateForm(this);
IPListBox.Items.AddRange(Global.Settings.BypassIPs.ToArray());
IPListBox.Items.AddRange(Global.Settings.TUNTAP.BypassIPs.Cast<object>().ToArray());
for (var i = 32; i >= 1; i--)
PrefixComboBox.Items.Add(i);
@@ -31,7 +32,7 @@ namespace Netch.Forms
if (!string.IsNullOrEmpty(IPTextBox.Text))
{
if (IPAddress.TryParse(IPTextBox.Text, out var address))
IPListBox.Items.Add(string.Format("{0}/{1}", address, PrefixComboBox.SelectedItem));
IPListBox.Items.Add($"{address}/{PrefixComboBox.SelectedItem}");
else
MessageBoxX.Show(i18N.Translate("Please enter a correct IP address"));
}
@@ -49,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.BypassIPs.Clear();
Global.Settings.TUNTAP.BypassIPs.Clear();
foreach (var ip in IPListBox.Items)
Global.Settings.BypassIPs.Add((string) ip);
Global.Settings.TUNTAP.BypassIPs.Add((string)ip);
Configuration.Save();
await Configuration.SaveAsync();
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}

View File

@@ -40,7 +40,7 @@ namespace Netch.Forms
this.richTextBox1.BackColor = System.Drawing.SystemColors.Control;
this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Top;
this.richTextBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.richTextBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.ReadOnly = true;
@@ -54,14 +54,14 @@ namespace Netch.Forms
this.checkBox1.AutoSize = true;
this.checkBox1.Location = new System.Drawing.Point(12, 297);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(102, 16);
this.checkBox1.Size = new System.Drawing.Size(101, 21);
this.checkBox1.TabIndex = 1;
this.checkBox1.Text = "Scroll to End";
this.checkBox1.UseVisualStyleBackColor = true;
//
// LogForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(454, 318);
this.ControlBox = false;
@@ -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
{
@@ -16,13 +17,13 @@ namespace Netch.Forms
_parent = parent;
}
protected override void OnLoad(EventArgs e)
protected override void OnLoad(EventArgs? e)
{
base.OnLoad(e);
Parent_Move(null!, null!);
}
private void Parent_Move(object sender, EventArgs e)
private void Parent_Move(object? sender, EventArgs? e)
{
var cl = Location;
var fl = _parent.Location;
@@ -32,26 +33,26 @@ namespace Netch.Forms
Location = cl;
}
private void Parent_Activated(object sender, EventArgs e)
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, System.EventArgs e)
private void richTextBox1_TextChanged(object? sender, EventArgs? e)
{
if (!checkBox1.Checked)
return;
@@ -60,19 +61,19 @@ 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;
_parent.Activated += Parent_Activated;
}
protected override void OnClosing(CancelEventArgs e)
protected override void OnClosing(CancelEventArgs? e)
{
_parent.Activated -= Parent_Activated;
_parent.LocationChanged -= Parent_Move;
_parent.SizeChanged -= Parent_Move;
base.OnClosing(e);
base.OnClosing(e!);
}
}
}

60
Netch/Forms/LogForm.resx Normal file
View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -38,15 +38,11 @@
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ManageSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UpdateServersFromSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem = 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.UpdateACLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.updateACLWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UninstallTapDriverToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.HelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.CheckForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -61,7 +57,7 @@
this.ModeLabel = new System.Windows.Forms.Label();
this.ServerLabel = new System.Windows.Forms.Label();
this.ProfileNameText = new System.Windows.Forms.TextBox();
this.ModeComboBox = new System.Windows.Forms.SearchComboBox();
this.ModeComboBox = new System.Windows.Forms.ComboBox();
this.ServerComboBox = new System.Windows.Forms.ComboBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.EditServerPictureBox = new System.Windows.Forms.PictureBox();
@@ -77,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();
@@ -171,8 +168,7 @@
//
this.SubscribeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ManageSubscribeLinksToolStripMenuItem,
this.UpdateServersFromSubscribeLinksToolStripMenuItem,
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem});
this.UpdateServersFromSubscribeLinksToolStripMenuItem});
this.SubscribeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.SubscribeToolStripMenuItem.Name = "SubscribeToolStripMenuItem";
this.SubscribeToolStripMenuItem.Size = new System.Drawing.Size(77, 21);
@@ -181,34 +177,24 @@
// ManageSubscribeLinksToolStripMenuItem
//
this.ManageSubscribeLinksToolStripMenuItem.Name = "ManageSubscribeLinksToolStripMenuItem";
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
this.ManageSubscribeLinksToolStripMenuItem.Text = "Manage Subscribe Links";
this.ManageSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.ManageSubscribeLinksToolStripMenuItem_Click);
//
// UpdateServersFromSubscribeLinksToolStripMenuItem
//
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksToolStripMenuItem";
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Text = "Update Servers From Subscribe Links";
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscribeLinksToolStripMenuItem_Click);
//
// UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem
//
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem";
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Text = "Update Servers From Subscribe Links With Proxy";
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem_Click);
//
// OptionsToolStripMenuItem
//
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.OpenDirectoryToolStripMenuItem,
this.ShowHideConsoleToolStripMenuItem,
this.CleanDNSCacheToolStripMenuItem,
this.UpdateACLToolStripMenuItem,
this.updateACLWithProxyToolStripMenuItem,
this.updatePACToolStripMenuItem,
this.UninstallServiceToolStripMenuItem,
this.UninstallTapDriverToolStripMenuItem,
this.removeNetchFirewallRulesToolStripMenuItem});
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.OptionsToolStripMenuItem.Name = "OptionsToolStripMenuItem";
@@ -222,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";
@@ -229,27 +222,6 @@
this.CleanDNSCacheToolStripMenuItem.Text = "Clean DNS Cache";
this.CleanDNSCacheToolStripMenuItem.Click += new System.EventHandler(this.CleanDNSCacheToolStripMenuItem_Click);
//
// UpdateACLToolStripMenuItem
//
this.UpdateACLToolStripMenuItem.Name = "UpdateACLToolStripMenuItem";
this.UpdateACLToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.UpdateACLToolStripMenuItem.Text = "Update ACL";
this.UpdateACLToolStripMenuItem.Click += new System.EventHandler(this.updateACLToolStripMenuItem_Click);
//
// updateACLWithProxyToolStripMenuItem
//
this.updateACLWithProxyToolStripMenuItem.Name = "updateACLWithProxyToolStripMenuItem";
this.updateACLWithProxyToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.updateACLWithProxyToolStripMenuItem.Text = "Update ACL with proxy";
this.updateACLWithProxyToolStripMenuItem.Click += new System.EventHandler(this.updateACLWithProxyToolStripMenuItem_Click);
//
// updatePACToolStripMenuItem
//
this.updatePACToolStripMenuItem.Name = "updatePACToolStripMenuItem";
this.updatePACToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.updatePACToolStripMenuItem.Text = "Update PAC";
this.updatePACToolStripMenuItem.Click += new System.EventHandler(this.updatePACToolStripMenuItem_Click);
//
// UninstallServiceToolStripMenuItem
//
this.UninstallServiceToolStripMenuItem.Name = "UninstallServiceToolStripMenuItem";
@@ -257,13 +229,6 @@
this.UninstallServiceToolStripMenuItem.Text = "Uninstall NF Service";
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
//
// UninstallTapDriverToolStripMenuItem
//
this.UninstallTapDriverToolStripMenuItem.Name = "UninstallTapDriverToolStripMenuItem";
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.UninstallTapDriverToolStripMenuItem.Text = "Uninstall TUN/TAP driver";
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.UninstallTapDriverToolStripMenuItem_Click);
//
// removeNetchFirewallRulesToolStripMenuItem
//
this.removeNetchFirewallRulesToolStripMenuItem.Name = "removeNetchFirewallRulesToolStripMenuItem";
@@ -414,9 +379,9 @@
//
// ModeComboBox
//
this.ModeComboBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
this.ModeComboBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.ModeComboBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.ModeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.ModeComboBox.FormattingEnabled = true;
this.ModeComboBox.IntegralHeight = false;
this.ModeComboBox.Location = new System.Drawing.Point(54, 33);
@@ -557,6 +522,7 @@
this.DownloadSpeedLabel,
this.UploadSpeedLabel,
this.blankToolStripStatusLabel,
this.HttpStatusLabel,
this.NatTypeStatusLabel,
this.NatTypeStatusLightLabel});
this.StatusStrip.Location = new System.Drawing.Point(0, 272);
@@ -596,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";
@@ -732,7 +707,7 @@
this.Controls.Add(this.MenuStrip);
this.Controls.Add(this.StatusStrip);
this.Controls.Add(this.flowLayoutPanel1);
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.MaximizeBox = false;
@@ -788,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.SearchComboBox 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;
@@ -801,7 +776,6 @@
private System.Windows.Forms.Label ProfileLabel;
private System.Windows.Forms.TextBox ProfileNameText;
private System.Windows.Forms.TableLayoutPanel ProfileTable;
private System.Windows.Forms.ToolStripMenuItem UninstallTapDriverToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem CheckForUpdatesToolStripMenuItem;
private System.Windows.Forms.ComboBox ServerComboBox;
private System.Windows.Forms.Label ServerLabel;
@@ -815,10 +789,7 @@
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.ToolStripMenuItem UninstallServiceToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem UpdateACLToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem updateACLWithProxyToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem;
private System.Windows.Forms.ToolStripStatusLabel UploadSpeedLabel;
private System.Windows.Forms.ToolStripStatusLabel UsedBandwidthLabel;
private System.Windows.Forms.ToolStripLabel NewVersionLabel;
@@ -831,6 +802,7 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
private System.Windows.Forms.ToolStripMenuItem updatePACToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem;
private System.Windows.Forms.ToolStripStatusLabel HttpStatusLabel;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,64 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

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,31 +1,31 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
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();
@@ -63,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);
@@ -117,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"));
@@ -133,14 +133,13 @@ namespace Netch.Forms.Mode
return;
}
var mode = new Models.Mode(fullName)
var mode = new Mode(fullName)
{
BypassChina = false,
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"));
@@ -149,7 +148,7 @@ namespace Netch.Forms.Mode
Close();
}
private void RemarkTextBox_TextChanged(object sender, EventArgs e)
private void RemarkTextBox_TextChanged(object? sender, EventArgs? e)
{
BeginInvoke(new Action(() =>
{
@@ -195,7 +194,8 @@ namespace Netch.Forms.Mode
foreach (string dir in Directory.GetDirectories(directory))
ScanDirectory(dir, list, maxCount);
list.AddRange(Directory.GetFiles(directory).Select(Path.GetFileName).Where(s => s.EndsWith(".exe")).Select(s => s.ToRegexString()));
list.AddRange(
Directory.GetFiles(directory).Select(s => Path.GetFileName(s)).Where(s => s.EndsWith(".exe")).Select(s => s.ToRegexString()));
if (maxCount != 0 && list.Count > maxCount)
throw new Exception("The number of results is greater than maxCount");
@@ -203,7 +203,7 @@ namespace Netch.Forms.Mode
private void ValidationButton_Click(object sender, EventArgs e)
{
if (NFController.CheckRules(Rules, out var results))
if (!NFController.CheckRules(Rules, out var results))
MessageBoxX.Show(NFController.GenerateInvalidRulesMessage(results), LogLevel.WARNING);
else
MessageBoxX.Show("Fine");

View File

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

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.
@@ -72,7 +72,7 @@ namespace Netch.Forms.Mode
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(84, 49);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(138, 20);
this.comboBox1.Size = new System.Drawing.Size(138, 25);
this.comboBox1.TabIndex = 11;
//
// FilenameLabel
@@ -80,7 +80,7 @@ namespace Netch.Forms.Mode
this.FilenameLabel.AutoSize = true;
this.FilenameLabel.Location = new System.Drawing.Point(12, 79);
this.FilenameLabel.Name = "FilenameLabel";
this.FilenameLabel.Size = new System.Drawing.Size(53, 12);
this.FilenameLabel.Size = new System.Drawing.Size(59, 17);
this.FilenameLabel.TabIndex = 6;
this.FilenameLabel.Text = "Filename";
//
@@ -89,7 +89,7 @@ namespace Netch.Forms.Mode
this.FilenameTextBox.Location = new System.Drawing.Point(84, 76);
this.FilenameTextBox.Name = "FilenameTextBox";
this.FilenameTextBox.ReadOnly = true;
this.FilenameTextBox.Size = new System.Drawing.Size(250, 21);
this.FilenameTextBox.Size = new System.Drawing.Size(250, 23);
this.FilenameTextBox.TabIndex = 5;
//
// ActionLabel
@@ -97,7 +97,7 @@ namespace Netch.Forms.Mode
this.ActionLabel.AutoSize = true;
this.ActionLabel.Location = new System.Drawing.Point(12, 52);
this.ActionLabel.Name = "ActionLabel";
this.ActionLabel.Size = new System.Drawing.Size(41, 12);
this.ActionLabel.Size = new System.Drawing.Size(44, 17);
this.ActionLabel.TabIndex = 0;
this.ActionLabel.Text = "Action";
//
@@ -105,7 +105,7 @@ namespace Netch.Forms.Mode
//
this.RemarkTextBox.Location = new System.Drawing.Point(84, 22);
this.RemarkTextBox.Name = "RemarkTextBox";
this.RemarkTextBox.Size = new System.Drawing.Size(250, 21);
this.RemarkTextBox.Size = new System.Drawing.Size(250, 23);
this.RemarkTextBox.TabIndex = 1;
this.RemarkTextBox.TextChanged += new System.EventHandler(this.RemarkTextBox_TextChanged);
//
@@ -114,7 +114,7 @@ namespace Netch.Forms.Mode
this.RemarkLabel.AutoSize = true;
this.RemarkLabel.Location = new System.Drawing.Point(12, 25);
this.RemarkLabel.Name = "RemarkLabel";
this.RemarkLabel.Size = new System.Drawing.Size(41, 12);
this.RemarkLabel.Size = new System.Drawing.Size(53, 17);
this.RemarkLabel.TabIndex = 0;
this.RemarkLabel.Text = "Remark";
//
@@ -161,12 +161,12 @@ namespace Netch.Forms.Mode
//
// Route
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
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,39 +1,23 @@
using System;
using System.IO;
using System.Windows.Forms;
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
{
class Item
private readonly TagItem<ModeType>[] _items =
{ new(ModeType.ProxyRuleIPs, "Proxy Rule IPs"), new(ModeType.BypassRuleIPs, "Bypass Rule IPs") };
private readonly Mode? _mode;
public RouteForm(Mode? mode = null)
{
private string _text;
public Item(int value, string text)
{
_text = text;
Value = value;
}
public string Text
{
get => i18N.Translate(_text);
set => _text = value;
}
public int Value { get; set; }
}
private readonly Item[] _items = {new(1, "Proxy Rule IPs"), new(2, "Bypass Rule IPs")};
private readonly Models.Mode? _mode;
public Route(Models.Mode? mode = null)
{
if (mode != null && mode.Type is not (1 or 2))
if (mode != null && mode.Type is not (ModeType.ProxyRuleIPs or ModeType.BypassRuleIPs))
throw new ArgumentOutOfRangeException();
_mode = mode;
@@ -41,8 +25,8 @@ namespace Netch.Forms.Mode
InitializeComponent();
Icon = Resources.icon;
comboBox1.DataSource = _items;
comboBox1.ValueMember = "Value";
comboBox1.DisplayMember = "Text";
comboBox1.ValueMember = nameof(TagItem<int>.Value);
comboBox1.DisplayMember = nameof(TagItem<int>.Text);
}
private void Route_Load(object sender, EventArgs e)
@@ -55,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);
@@ -78,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"));
@@ -95,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"));
@@ -110,12 +94,9 @@ namespace Netch.Forms.Mode
Close();
}
private void RemarkTextBox_TextChanged(object sender, EventArgs e)
private void RemarkTextBox_TextChanged(object? sender, EventArgs? e)
{
BeginInvoke(new Action(() =>
{
FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text);
}));
BeginInvoke(new Action(() => { FilenameTextBox.Text = ModeEditorUtils.GetCustomModeRelativePath(RemarkTextBox.Text); }));
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

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

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,11 @@ using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using Serilog;
namespace Netch.Forms
{
@@ -26,25 +27,18 @@ namespace Netch.Forms
#region General
BindTextBox<ushort>(Socks5PortTextBox,
p => p.ToString() != HTTPPortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
p => p.ToString() != HTTPPortTextBox.Text,
p => Global.Settings.Socks5LocalPort = p,
Global.Settings.Socks5LocalPort);
BindTextBox<ushort>(HTTPPortTextBox,
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
p => p.ToString() != Socks5PortTextBox.Text,
p => Global.Settings.HTTPLocalPort = p,
Global.Settings.HTTPLocalPort);
BindTextBox<ushort>(RedirectorTextBox,
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != HTTPPortTextBox.Text,
p => Global.Settings.RedirectorTCPPort = p,
Global.Settings.RedirectorTCPPort);
BindCheckBox(AllowDevicesCheckBox,
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
Global.Settings.LocalAddress switch {"127.0.0.1" => false, "0.0.0.0" => true, _ => false});
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);
@@ -52,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);
@@ -64,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;
}
@@ -97,33 +91,28 @@ namespace Netch.Forms
Global.Settings.STUN_Server + ":" + Global.Settings.STUN_Server_Port,
stuns);
BindTextBox<string>(AclAddrTextBox, s => true, s => Global.Settings.ACL = s, Global.Settings.ACL);
BindListComboBox(LanguageComboBox,
o => Global.Settings.Language = o.ToString(),
i18N.GetTranslateList().Cast<object>().ToArray(),
Global.Settings.Language);
BindListComboBox(LanguageComboBox, o => Global.Settings.Language = o.ToString(), i18N.GetTranslateList(), Global.Settings.Language);
#endregion
#region Process Mode
BindCheckBox(DNSRedirectorCheckBox, b => Global.Settings.RedirectDNS = b, Global.Settings.RedirectDNS);
BindListComboBox(ProcessFilterProtocolComboBox,
s => Global.Settings.Redirector.FilterProtocol = (PortType)Enum.Parse(typeof(PortType), s.ToString(), false),
Enum.GetNames(typeof(PortType)),
Global.Settings.Redirector.FilterProtocol.ToString());
BindTextBox(RDRDNSTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.RedirectDNSAddr = s, Global.Settings.RedirectDNSAddr);
BindCheckBox(DNSHijackCheckBox, b => Global.Settings.Redirector.DNSHijack = b, Global.Settings.Redirector.DNSHijack);
BindCheckBox(ICMPRedirectorCheckBox, b => Global.Settings.RedirectICMP = b, Global.Settings.RedirectICMP);
BindTextBox(DNSHijackHostTextBox, s => true, s => Global.Settings.Redirector.DNSHijackHost = s, Global.Settings.Redirector.DNSHijackHost);
BindTextBox(ModifiedICMPTextBox, s => DnsUtils.TrySplit(s, out _, 2), s => Global.Settings.RedirectICMPAddr = s, Global.Settings.RedirectICMPAddr);
BindCheckBox(FilterICMPCheckBox, b => Global.Settings.Redirector.FilterICMP = b, Global.Settings.Redirector.FilterICMP);
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.RedirectorSS = s, Global.Settings.RedirectorSS);
BindTextBox(ICMPDelayTextBox, s => int.TryParse(s, out _), s => { }, Global.Settings.Redirector.ICMPDelay);
BindCheckBox(ChildProcessHandleCheckBox, s => Global.Settings.ChildProcessHandle = s, Global.Settings.ChildProcessHandle);
BindListComboBox(ProcessProxyProtocolComboBox,
s => Global.Settings.ProcessProxyProtocol = (PortType) Enum.Parse(typeof(PortType), s.ToString(), false),
Enum.GetNames(typeof(PortType)).Cast<object>().ToArray(),
Global.Settings.ProcessProxyProtocol.ToString());
BindCheckBox(ChildProcessHandleCheckBox,
s => Global.Settings.Redirector.ChildProcessHandle = s,
Global.Settings.Redirector.ChildProcessHandle);
#endregion
@@ -147,16 +136,15 @@ namespace Netch.Forms
BindCheckBox(UseCustomDNSCheckBox, b => { Global.Settings.TUNTAP.UseCustomDNS = b; }, Global.Settings.TUNTAP.UseCustomDNS);
BindTextBox(TUNTAPDNSTextBox,
s => !UseCustomDNSCheckBox.Checked || DnsUtils.TrySplit(s, out _, 2),
_ => true,
s =>
{
if (UseCustomDNSCheckBox.Checked)
Global.Settings.TUNTAP.DNS = DnsUtils.Split(s).ToList();
Global.Settings.TUNTAP.HijackDNS = s;
},
DnsUtils.Join(Global.Settings.TUNTAP.DNS));
Global.Settings.TUNTAP.HijackDNS);
BindCheckBox(ProxyDNSCheckBox, b => Global.Settings.TUNTAP.ProxyDNS = b, Global.Settings.TUNTAP.ProxyDNS);
BindCheckBox(UseFakeDNSCheckBox, b => Global.Settings.TUNTAP.UseFakeDNS = b, Global.Settings.TUNTAP.UseFakeDNS);
#endregion
@@ -213,21 +201,20 @@ 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, s => 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(ChinaDNSTextBox,
s => IPAddress.TryParse(s, out _),
s => Global.Settings.AioDNS.ChinaDNS = s,
Global.Settings.AioDNS.ChinaDNS);
BindTextBox(OtherDNSTextBox, _ => true, s => Global.Settings.AioDNS.OtherDNS = s, Global.Settings.AioDNS.OtherDNS);
BindTextBox(OtherDNSTextBox,
s => IPAddress.TryParse(s, out _),
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
}
@@ -235,13 +222,12 @@ namespace Netch.Forms
private void SettingForm_Load(object sender, EventArgs e)
{
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Flags.SupportFakeDns)));
}
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object? sender, EventArgs? e)
{
if (UseCustomDNSCheckBox.Checked)
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any() ? DnsUtils.Join(Global.Settings.TUNTAP.DNS) : "1.1.1.1";
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.HijackDNS;
else
TUNTAPDNSTextBox.Text = "AioDNS";
}
@@ -253,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));
@@ -277,7 +263,7 @@ namespace Netch.Forms
Utils.Utils.RegisterNetchStartupItem();
Configuration.Save();
await Configuration.SaveAsync();
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}
@@ -297,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
{
@@ -305,29 +291,34 @@ 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(ComboBox control, Action<object> save, object[] values, object value, string propertyName = "SelectedItem")
private void BindListComboBox<T>(ComboBox comboBox, Action<T> save, IEnumerable<T> values, T value) where T : notnull
{
if (control.DropDownStyle != ComboBoxStyle.DropDownList)
if (comboBox.DropDownStyle != ComboBoxStyle.DropDownList)
throw new ArgumentOutOfRangeException();
control.Items.AddRange(values);
_saveActions.Add(control, c => save.Invoke(((ComboBox) c).SelectedItem));
Load += (_, _) => { control.SelectedItem = value; };
var tagItems = values.Select(o => new TagItem<T>(o, o.ToString()!)).ToArray();
comboBox.Items.AddRange(tagItems.Cast<object>().ToArray());
comboBox.ValueMember = nameof(TagItem<T>.Value);
comboBox.DisplayMember = nameof(TagItem<T>.Text);
_saveActions.Add(comboBox, c => save.Invoke(((TagItem<T>)((ComboBox)c).SelectedItem).Value));
Load += (_, _) => { comboBox.SelectedItem = tagItems.SingleOrDefault(t => t.Value.Equals(value)); };
}
private void BindComboBox(ComboBox control, Func<string, bool> check, Action<string> save, string value, object[]? values = null)
@@ -335,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,64 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

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

46
Netch/Interops/AioDNS.cs Normal file
View File

@@ -0,0 +1,46 @@
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Serilog;
namespace Netch.Interops
{
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);
[DllImport(aiodns_bin, EntryPoint = "aiodns_init", CallingConvention = CallingConvention.Cdecl)]
public static extern bool Init();
[DllImport(aiodns_bin, EntryPoint = "aiodns_free", CallingConvention = CallingConvention.Cdecl)]
public static extern void Free();
public enum NameList
{
TYPE_REST,
TYPE_ADDR,
TYPE_LIST,
TYPE_CDNS,
TYPE_ODNS
}
}
}

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

@@ -0,0 +1,80 @@
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Serilog;
namespace Netch.Interops
{
public static class Redirector
{
public enum NameList
{
TYPE_FILTERLOOPBACK,
TYPE_FILTERICMP,
TYPE_FILTERTCP,
TYPE_FILTERUDP,
TYPE_CLRNAME,
TYPE_ADDNAME,
TYPE_BYPNAME,
TYPE_DNSHOST,
TYPE_TCPLISN,
TYPE_TCPTYPE,
TYPE_TCPHOST,
TYPE_TCPUSER,
TYPE_TCPPASS,
TYPE_TCPMETH,
TYPE_TCPPROT,
TYPE_TCPPRPA,
TYPE_TCPOBFS,
TYPE_TCPOBPA,
TYPE_UDPLISN,
TYPE_UDPTYPE,
TYPE_UDPHOST,
TYPE_UDPUSER,
TYPE_UDPPASS,
TYPE_UDPMETH,
TYPE_UDPPROT,
TYPE_UDPPRPA,
TYPE_UDPOBFS,
TYPE_UDPOBPA
}
public static bool Dial(NameList name, string value)
{
Log.Verbose($"[Redirector] Dial {name}: {value}");
return aio_dial(name, value);
}
public static async Task<bool> InitAsync()
{
return await Task.Run(aio_init).ConfigureAwait(false);
}
public static async Task<bool> FreeAsync()
{
return await Task.Run(aio_free).ConfigureAwait(false);
}
public const int UdpNameListOffset = (int)NameList.TYPE_UDPLISN - (int)NameList.TYPE_TCPLISN;
private const string Redirector_bin = "Redirector.bin";
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool aio_dial(NameList name, [MarshalAs(UnmanagedType.LPWStr)] string value);
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool aio_init();
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool aio_free();
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern ulong aio_getUP();
[DllImport(Redirector_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern ulong aio_getDL();
}
}

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

@@ -0,0 +1,75 @@
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Serilog;
namespace Netch.Interops
{
public static class tun2socks
{
public enum NameList
{
TYPE_BYPBIND,
TYPE_BYPLIST,
TYPE_DNSADDR,
TYPE_ADAPMTU,
TYPE_TCPREST,
TYPE_TCPTYPE,
TYPE_TCPHOST,
TYPE_TCPUSER,
TYPE_TCPPASS,
TYPE_TCPMETH,
TYPE_TCPPROT,
TYPE_TCPPRPA,
TYPE_TCPOBFS,
TYPE_TCPOBPA,
TYPE_UDPREST,
TYPE_UDPTYPE,
TYPE_UDPHOST,
TYPE_UDPUSER,
TYPE_UDPPASS,
TYPE_UDPMETH,
TYPE_UDPPROT,
TYPE_UDPPRPA,
TYPE_UDPOBFS,
TYPE_UDPOBPA
}
public static bool Dial(NameList name, string 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 async Task<bool> FreeAsync()
{
return await Task.Run(tun_free).ConfigureAwait(false);
}
private const string tun2socks_bin = "tun2socks.bin";
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool tun_dial(NameList name, byte[] value);
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool tun_init();
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern bool tun_free();
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
public static extern ulong tun_luid();
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern ulong tun_getUP();
[DllImport(tun2socks_bin, CallingConvention = CallingConvention.Cdecl)]
private static extern ulong tun_getDL();
}
}

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,25 +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)
{
var split = input.Split('-');
var dotNetVersion = Version.Parse(split[0]);
var preRelease = split.ElementAtOrDefault(1) ?? string.Empty;
if (value == null)
throw new ArgumentNullException(nameof(value));
return new SuffixVersion(dotNetVersion, preRelease);
var strings = value.Split('-');
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);
@@ -34,12 +63,11 @@ namespace Netch.Models.GitHubRelease
}
catch (Exception)
{
result = default;
return false;
}
}
public int CompareTo(object obj)
public int CompareTo(object? obj)
{
if (obj is not SuffixVersion version)
throw new ArgumentOutOfRangeException();
@@ -59,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,12 +0,0 @@
using System.Collections.Generic;
namespace Netch.Models.GitHubRelease
{
public class VersionComparer : IComparer<object>
{
public int Compare(object x, object 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,15 +0,0 @@
using System.Net;
using System.Net.NetworkInformation;
namespace Netch.Models
{
public interface IAdapter
{
public abstract int Index { get; }
public abstract IPAddress Gateway { get; }
public abstract NetworkInterface NetworkInterface { get; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace Netch.Models
{
public class MessageException : Exception
{
public MessageException()
{
}
public MessageException(string message) : base(message)
{
}
}
}

View File

@@ -3,180 +3,121 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Netch.Controllers;
using Netch.Enums;
using Netch.Utils;
namespace Netch.Models
{
public class Mode
{
private readonly Lazy<List<string>> _lazyRule;
private List<string>? _content;
public string? FullName { get; private set; }
public Mode(string? fullName = default)
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;
// TODO throw NotSupportedModeTypeException
var bypassChinaResult = int.TryParse(split.ElementAtOrDefault(2), out var bypassChina);
BypassChina = this.ClientRouting() && bypassChinaResult && bypassChina == 1;
Load();
}
/// <summary>
/// 规则
/// </summary>
public List<string> Rule => _lazyRule.Value;
public string? FullName { get; }
/// <summary>
/// 绕过中国0. 不绕过 1. 绕过)
/// </summary>
public bool BypassChina { get; set; }
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}, {(BypassChina ? 1 : 0)}{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;
}
/// Socks5 分流是否能被有效实施
public static bool ClientRouting(this Mode mode)
{
return mode.Type is not (1 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,69 +0,0 @@
using System;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using Microsoft.Win32;
using Netch.Controllers;
using Netch.Utils;
using Vanara.PInvoke;
namespace Netch.Models
{
public class OutboundAdapter : IAdapter
{
public OutboundAdapter(bool logging = true)
{
// 寻找出口适配器
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);
Index = (int) pRoute.dwForwardIfIndex;
Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
_parametersRegistry =
Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{NetworkInterface.Id}", true)!;
if (logging)
{
Logging.Info($"出口 网关 地址:{Gateway}");
Logging.Info($"出口适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}");
}
}
/// <summary>
/// 索引
/// </summary>
public int Index { get; }
/// <summary>
/// 网关
/// </summary>
public IPAddress Gateway { get; }
public NetworkInterface NetworkInterface { get; }
public string DNS
{
get
{
try
{
return (string) _parametersRegistry.GetValue("NameServer");
}
catch
{
return string.Empty;
}
}
set => _parametersRegistry.SetValue("NameServer", value, RegistryValueKind.String);
}
private readonly RegistryKey _parametersRegistry;
}
}

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
@@ -6,7 +7,7 @@ namespace Netch.Models
/// <summary>
/// TUN/TAP 适配器配置类
/// </summary>
public class TUNTAPConfig
public class TUNConfig
{
/// <summary>
/// 地址
@@ -16,7 +17,7 @@ namespace Netch.Models
/// <summary>
/// DNS
/// </summary>
public List<string> DNS { get; set; } = new();
public string HijackDNS { get; set; } = "tcp://1.1.1.1:53";
/// <summary>
/// 网关
@@ -39,9 +40,9 @@ namespace Netch.Models
public bool UseCustomDNS { get; set; } = false;
/// <summary>
/// 使用Fake DNS
/// 全局绕过 IP 列表
/// </summary>
public bool UseFakeDNS { get; set; } = false;
public List<string> BypassIPs { get; set; } = new();
}
public class KcpConfig
@@ -71,18 +72,45 @@ namespace Netch.Models
public bool V2rayNShareLink { get; set; } = true;
public bool XrayCone { get; set; } = false;
public bool XrayCone { get; set; } = true;
}
public class AioDNSConfig
{
public string ChinaDNS { get; set; } = "223.5.5.5";
public string ChinaDNS { get; set; } = "tcp://223.5.5.5:53";
public string OtherDNS { get; set; } = "1.1.1.1";
public string OtherDNS { get; set; } = "tcp://1.1.1.1:53";
public string Protocol { get; set; } = "tcp";
public ushort ListenPort { get; set; } = 253;
}
public string RulePath { get; set; } = "bin\\china_site_list";
public class RedirectorConfig
{
/// <summary>
/// 不代理TCP
/// </summary>
public PortType FilterProtocol { get; set; } = PortType.Both;
/// <summary>
/// 是否开启DNS转发
/// </summary>
public bool DNSHijack { get; set; } = true;
/// <summary>
/// 转发DNS地址
/// </summary>
public string DNSHijackHost { get; set; } = "1.1.1.1:53";
[JsonIgnore]
public int ICMPDelay { get; } = 0;
public bool FilterICMP { get; set; } = false;
/// <summary>
/// 是否代理子进程
/// </summary>
[JsonIgnore]
public bool ChildProcessHandle { get; set; } = false;
}
/// <summary>
@@ -90,23 +118,15 @@ namespace Netch.Models
/// </summary>
public class Setting
{
public RedirectorConfig Redirector { get; set; } = new();
/// <summary>
/// 服务器列表
/// </summary>
public List<Server> Server { get; set; } = new();
/// <summary>
/// ACL规则
/// </summary>
public string ACL { get; set; } = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
public AioDNSConfig AioDNS { get; set; } = new();
/// <summary>
/// 全局绕过 IP 列表
/// </summary>
public List<string> BypassIPs { get; set; } = new();
/// <summary>
/// 是否检查 Beta 更新
/// </summary>
@@ -150,42 +170,7 @@ namespace Netch.Models
/// <summary>
/// 模式选择位置
/// </summary>
public int ModeComboBoxSelectedIndex { get; set; } = 0;
/// <summary>
/// 转发DNS地址
/// </summary>
public string RedirectDNSAddr { get; set; } = "8.8.8.8";
/// <summary>
/// 是否开启DNS转发
/// </summary>
public bool RedirectDNS { get; set; } = false;
/// <summary>
/// 转发ICMP地址
/// </summary>
public string RedirectICMPAddr { get; set; } = "1.2.4.8";
/// <summary>
/// 是否开启ICMP转发
/// </summary>
public bool RedirectICMP { get; set; } = false;
/// <summary>
/// GFWList
/// </summary>
public string PAC { get; set; } = "https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac";
/// <summary>
/// PAC端口
/// </summary>
public ushort Pac_Port { get; set; } = 2803;
/// <summary>
/// 不代理TCP
/// </summary>
public PortType ProcessProxyProtocol { get; set; } = PortType.Both;
public int ModeComboBoxSelectedIndex { get; set; } = -1;
/// <summary>
/// 快捷配置数量
@@ -202,31 +187,11 @@ namespace Netch.Models
/// </summary>
public byte ProfileTableColumnCount { get; set; } = 5;
/// <summary>
/// 是否使用RDR内置SS
/// </summary>
public bool RedirectorSS { get; set; } = false;
/// <summary>
/// 是否代理子进程
/// </summary>
public bool ChildProcessHandle { get; set; } = false;
/// <summary>
/// Redirector TCP 占用端口
/// </summary>
public ushort RedirectorTCPPort { get; set; } = 3901;
/// <summary>
/// 网页请求超时 毫秒
/// </summary>
public int RequestTimeout { get; set; } = 10000;
/// <summary>
/// 解析服务器主机名
/// </summary>
public bool ResolveServerHostname { get; set; } = false;
/// <summary>
/// 是否开机启动软件
/// </summary>
@@ -235,7 +200,7 @@ namespace Netch.Models
/// <summary>
/// 服务器选择位置
/// </summary>
public int ServerComboBoxSelectedIndex { get; set; } = 0;
public int ServerComboBoxSelectedIndex { get; set; } = -1;
/// <summary>
/// 服务器测试方式 false.ICMPing true.TCPing
@@ -280,25 +245,26 @@ namespace Netch.Models
/// <summary>
/// TUNTAP 适配器配置
/// </summary>
public TUNTAPConfig TUNTAP { get; set; } = new();
public TUNConfig TUNTAP { get; set; } = new();
/// <summary>
/// 是否打开软件时更新订阅
/// </summary>
public bool UpdateServersWhenOpened { get; set; } = false;
/// <summary>
/// 使用代理更新订阅
/// </summary>
public bool UseProxyToUpdateSubscription { get; set; } = false;
public V2rayConfig V2RayConfig { get; set; } = new();
public bool? AlwaysStartPACServer { get; set; }
public bool NoSupportDialog { get; set; } = false;
public Setting Clone()
{
return (Setting) MemberwiseClone();
return (Setting)MemberwiseClone();
}
public void Set(Setting value)
{
foreach (var p in typeof(Setting).GetProperties())
p.SetValue(this, p.GetValue(value));
}
}
}

View File

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

19
Netch/Models/TagItem.cs Normal file
View File

@@ -0,0 +1,19 @@
using Netch.Utils;
namespace Netch.Models
{
internal class TagItem<T>
{
private readonly string _text;
public TagItem(T value, string text)
{
_text = text;
Value = value;
}
public string Text => i18N.Translate(_text);
public T Value { get; }
}
}

View File

@@ -1,30 +0,0 @@
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using Netch.Controllers;
using Netch.Utils;
namespace Netch.Models
{
public class TapAdapter : IAdapter
{
public TapAdapter()
{
Index = -1;
ComponentID = TUNTAP.GetComponentID() ?? throw new MessageException("TAP 适配器未安装");
// 根据 ComponentID 寻找 Tap适配器
NetworkInterface = NetworkInterface.GetAllNetworkInterfaces().First(i => i.Id == ComponentID);
Index = NetworkInterface.GetIPProperties().GetIPv4Properties().Index;
Logging.Info($"TAP 适配器:{NetworkInterface.Name} {NetworkInterface.Id} {NetworkInterface.Description}, index: {Index}");
}
public string ComponentID { get; }
public int Index { get; }
public IPAddress Gateway => IPAddress.Parse(Global.Settings.TUNTAP.Gateway);
public NetworkInterface NetworkInterface { get; }
}
}

View File

@@ -4,37 +4,7 @@ namespace Netch
{
public static class NativeMethods
{
/// <summary>
/// 创建路由规则
/// </summary>
/// <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(string address, int cidr, string gateway, int index, int metric = 0);
/// <summary>
/// 删除路由规则
/// </summary>
/// <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(string address, int cidr, string gateway, int index, int metric = 0);
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();
[DllImport("kernel32.dll")]
public static extern bool AllocConsole();
[DllImport("kernel32.dll")]
public static extern bool AttachConsole(int dwProcessId);
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,19 +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 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>
/// 应用程序的主入口点
@@ -21,32 +37,26 @@ namespace Netch
[STAThread]
public static void Main(string[] args)
{
#if DEBUG
AttachConsole();
#else
if (args.Contains(Constants.Parameter.Console))
AttachConsole();
#endif
if (args.Contains(Constants.Parameter.ForceUpdate))
Flags.AlwaysShowNewVersionFound = true;
// 设置当前目录
Directory.SetCurrentDirectory(Global.NetchDir);
Environment.SetEnvironmentVariable("PATH",
Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ";" + Path.Combine(Global.NetchDir, "bin"),
EnvironmentVariableTarget.Process);
var binPath = Path.Combine(Global.NetchDir, "bin");
Environment.SetEnvironmentVariable("PATH", $"{Environment.GetEnvironmentVariable("PATH")};{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)
{
@@ -56,7 +66,6 @@ namespace Netch
}
SingleInstance.ArgumentsReceived.Subscribe(SingleInstance_ArgumentsReceived);
SingleInstance.ListenForArgumentsFromSuccessiveInstances();
// 清理上一次的日志文件,防止淤积占用磁盘空间
if (Directory.Exists("logging"))
@@ -70,6 +79,10 @@ namespace Netch
dir.Delete(true);
}
InitConsole();
CreateLogger();
// 加载语言
i18N.Load(Global.Settings.Language);
@@ -79,28 +92,96 @@ 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();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(Global.MainForm);
}
private static void AttachConsole()
private static void LogEnvironment()
{
if (!NativeMethods.AttachConsole(-1))
NativeMethods.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,139 +1,84 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\common.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net48</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>
<!-- <EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>-->
<NoWarn>VSTHRD100</NoWarn>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<AnalysisMode>Default</AnalysisMode>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningsAsErrors />
<NoWarn />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<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="Microsoft.Win32.Registry" Version="5.0.0" />
<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.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="5.0.1" />
<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="WindowsProxy" Version="5.0.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
<!-- .NET Framework -->
<PackageReference Include="ILMerge" Version="3.0.41" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' != 'net'">
<!-- .NET Core -->
<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="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />
<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" />
<ProjectReference Include="..\SearchComboBox\SearchComboBox.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">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Remove="Forms\LogForm.resx" />
<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;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改

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