mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac2e5e943e | ||
|
|
0957514e05 | ||
|
|
35b9f168ff | ||
|
|
ce15e9468e | ||
|
|
4c8508a838 | ||
|
|
f931adb005 | ||
|
|
d4f829d4bd | ||
|
|
51d4ba0fdb | ||
|
|
ca0870889a | ||
|
|
ac3e39e9cd | ||
|
|
84765ab96d | ||
|
|
a18851af15 | ||
|
|
42366abcca | ||
|
|
cec8358922 | ||
|
|
db8e964351 | ||
|
|
ad3053298a | ||
|
|
669ca4902f | ||
|
|
272bf61b0f | ||
|
|
0051e7bb50 | ||
|
|
aa5faa9af6 | ||
|
|
a92d1c8244 | ||
|
|
6bdcc7ce04 | ||
|
|
b5c7ca4c1a | ||
|
|
7c318a9e49 | ||
|
|
f9724f77c2 | ||
|
|
5d8bbe3518 | ||
|
|
e9f0a5b2f8 | ||
|
|
9d086336ea | ||
|
|
b31bedbc82 | ||
|
|
7f15042c03 | ||
|
|
2c4728f13c | ||
|
|
a2f5c9ab27 | ||
|
|
583bf31c92 | ||
|
|
0275b7718f | ||
|
|
0a226fab22 | ||
|
|
77680e2c02 | ||
|
|
2afc5ff21a | ||
|
|
4f4882d7f7 | ||
|
|
41fdf94a16 | ||
|
|
a3e8826105 | ||
|
|
b7bcb46c78 | ||
|
|
5e27b6a1eb | ||
|
|
a5903f5f57 | ||
|
|
39eb1b4eef | ||
|
|
23bcac0d5d | ||
|
|
38480776f0 | ||
|
|
bcccb80ece | ||
|
|
513d0b01a7 | ||
|
|
a3d309113c | ||
|
|
e77a40966c | ||
|
|
670cb06e4a | ||
|
|
59b4ba578b | ||
|
|
5ed25de9ee | ||
|
|
464abef28a | ||
|
|
79a7273af2 | ||
|
|
7d44821e57 | ||
|
|
ca3502a284 | ||
|
|
415fc5fa8f | ||
|
|
cfd458ffbd | ||
|
|
3be5f10ed8 | ||
|
|
41479275da | ||
|
|
639fcf9575 | ||
|
|
1eebb61d04 | ||
|
|
a2a66675c2 | ||
|
|
850393ab71 | ||
|
|
ea0dd3cd4a | ||
|
|
c2afc1b014 | ||
|
|
7b9d9a6d57 | ||
|
|
860482402a | ||
|
|
a58f7c7b98 | ||
|
|
6afc5e5e4d | ||
|
|
98a5e91dd2 | ||
|
|
9581a41007 | ||
|
|
d85b478868 | ||
|
|
628dd6963a | ||
|
|
5ae6f73062 | ||
|
|
50b07ebabb | ||
|
|
21f2f8da5e | ||
|
|
cfc070b1ef | ||
|
|
a4f024df69 | ||
|
|
6754268714 | ||
|
|
642cd57b71 | ||
|
|
39ea679298 | ||
|
|
1091486877 | ||
|
|
d805a4fccd | ||
|
|
902f78b563 | ||
|
|
159fbdd58d | ||
|
|
0c5464f833 | ||
|
|
b019362f5f | ||
|
|
241371c6f7 | ||
|
|
9b3f5f456f | ||
|
|
c04b8f6ffd | ||
|
|
9d6b6d15d7 | ||
|
|
39081c0a6f | ||
|
|
812fab6322 | ||
|
|
bfadb181c4 | ||
|
|
52ac05ee17 | ||
|
|
c774122fdb | ||
|
|
8e223faa71 | ||
|
|
7b0f0f35cc | ||
|
|
89ce721d4c | ||
|
|
2247a75269 | ||
|
|
c1e9856e92 | ||
|
|
41e74e0794 | ||
|
|
6f8214951a | ||
|
|
0fc5b77004 | ||
|
|
34cbcbfb0f | ||
|
|
1ad4a08a85 | ||
|
|
8e0bc8e260 | ||
|
|
bae9ecfe88 | ||
|
|
3ca3e45ce2 | ||
|
|
bcb220bc4b | ||
|
|
c50eb32828 | ||
|
|
b96f171b47 | ||
|
|
4fbbd1dbd4 | ||
|
|
2ad394dfde | ||
|
|
421b35a797 | ||
|
|
25612df086 | ||
|
|
4ac5065ce4 | ||
|
|
d4b97a99e0 | ||
|
|
3d49fe0338 |
@@ -6,4 +6,54 @@ root = true
|
||||
# all files
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
|
||||
# Microsoft .NET properties
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
# ReSharper properties
|
||||
resharper_blank_lines_after_block_statements = 0
|
||||
resharper_csharp_blank_lines_around_field = 0
|
||||
resharper_csharp_blank_lines_around_invocable = 0
|
||||
resharper_csharp_blank_lines_around_type = 0
|
||||
resharper_csharp_int_align_comments = true
|
||||
resharper_csharp_max_line_length = 368
|
||||
resharper_csharp_wrap_lines = false
|
||||
resharper_place_expr_accessor_on_single_line = true
|
||||
resharper_place_expr_method_on_single_line = true
|
||||
resharper_place_field_attribute_on_same_line = false
|
||||
resharper_place_simple_embedded_statement_on_same_line = false
|
||||
resharper_place_simple_initializer_on_single_line = false
|
||||
resharper_use_indent_from_vs = false
|
||||
resharper_wrap_array_initializer_style = chop_if_long
|
||||
resharper_wrap_object_and_collection_initializer_style = chop_always
|
||||
|
||||
# ReSharper inspection severities
|
||||
resharper_arrange_redundant_parentheses_highlighting = hint
|
||||
resharper_arrange_this_qualifier_highlighting = hint
|
||||
resharper_arrange_type_member_modifiers_highlighting = hint
|
||||
resharper_arrange_type_modifiers_highlighting = hint
|
||||
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
|
||||
resharper_built_in_type_reference_style_highlighting = hint
|
||||
resharper_redundant_base_qualifier_highlighting = warning
|
||||
resharper_suggest_var_or_type_built_in_types_highlighting = hint
|
||||
resharper_suggest_var_or_type_elsewhere_highlighting = hint
|
||||
resharper_suggest_var_or_type_simple_types_highlighting = hint
|
||||
resharper_web_config_module_not_resolved_highlighting = warning
|
||||
resharper_web_config_type_not_resolved_highlighting = warning
|
||||
resharper_web_config_wrong_module_highlighting = warning
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -2,15 +2,13 @@
|
||||
name: 'Bug report'
|
||||
about: 'Create a report to help us improve'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
labels: '需要核实'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Make sure you have read the readme, searched and read the issues related to yours. Otherwise it will be considered as a duplicate which will be closed immediately.**
|
||||
|
||||
**All issues about `bin/Redirector.exe` should be discussed at [issue #152](https://github.com/NetchX/Netch/issues/152).**
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.zh-CN.md
vendored
@@ -2,15 +2,13 @@
|
||||
name: '错误报告'
|
||||
about: '创建错误报告以帮助我们改进'
|
||||
title: ''
|
||||
labels: 'Status: Review Needed'
|
||||
labels: '需要核实'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**确保你已经看过 readme,也搜索并阅读过和你遇到的情况相关的问题。否则会被认为是重复的并被立刻关闭。**
|
||||
|
||||
**所有关于 `bin/Redirector.exe` 的问题,请在 [issue #152](https://github.com/NetchX/Netch/issues/152) 中讨论**
|
||||
|
||||
**错误描述**
|
||||
对错误的清晰简洁描述
|
||||
|
||||
|
||||
43
.github/workflows/build.yml
vendored
43
.github/workflows/build.yml
vendored
@@ -14,26 +14,32 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Build Solution
|
||||
shell: pwsh
|
||||
run: .\BUILD.ps1
|
||||
|
||||
- name: Upload Artifact
|
||||
continue-on-error: true
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: Netch\bin\x64\Release
|
||||
|
||||
- name: Package
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
.\BUILD.ps1
|
||||
New-Item -ItemType Directory -Path C:\builtfiles -Force > $null
|
||||
7z a -mx9 C:\builtfiles\Netch.7z .\Netch\bin\x64\Release\
|
||||
7z rn C:\builtfiles\Netch.7z Release Netch
|
||||
echo "Netch_SHA256=$(.\GetSHA256.ps1 C:\builtfiles\Netch.7z)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
echo "Netch_EXE_SHA256=$(.\GetSHA256.ps1 Netch\bin\x64\Release\Netch.exe)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: Netch\bin\x64\Release
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
with:
|
||||
name: ${{ env.GITHUB_TAG_NAME }}
|
||||
prerelease: true
|
||||
@@ -49,23 +55,4 @@ jobs:
|
||||
## 校验和
|
||||
| 文件名 | SHA256 |
|
||||
| :- | :- |
|
||||
| Netch.7z | ${{ env.Netch_SHA256 }} |
|
||||
|
||||
# Deploy:
|
||||
# needs: [build]
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Download Artifacts
|
||||
# uses: actions/download-artifact@v1
|
||||
# with:
|
||||
# name: Netch
|
||||
|
||||
# - name: Pushes to another repository
|
||||
# uses: peaceiris/actions-gh-pages@v3
|
||||
# with:
|
||||
# personal_token: ${{ secrets.ACCESS_TOKEN }}
|
||||
# publish_branch: repo
|
||||
# publish_dir: ./Netch
|
||||
# external_repository: ${{ github.repository_owner }}/NetchReleases
|
||||
# user_name: 'github-actions[bot]'
|
||||
# user_email: 'github-actions[bot]@users.noreply.github.com'
|
||||
| Netch.7z | ${{ env.Netch_SHA256 }} |
|
||||
13
Netch.sln
13
Netch.sln
@@ -5,11 +5,11 @@ VisualStudioVersion = 16.0.29009.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{4B041B91-5790-4571-8C58-C63FFE4BC9F8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetchLib", "NetchLib\NetchLib.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetchLib", "NetchLib\NetchLib.csproj", "{A8715AF4-ACC6-43F9-9381-4294C5360623}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetchUpdater", "NetchUpdater\NetchUpdater.csproj", "{828318A8-9B90-4A5F-BD6B-E632CC9D8933}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetchUpdater", "NetchUpdater\NetchUpdater.csproj", "{828318A8-9B90-4A5F-BD6B-E632CC9D8933}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{53397641-35CA-4336-8E22-2CE12EF476AC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -29,10 +29,9 @@ Global
|
||||
{828318A8-9B90-4A5F-BD6B-E632CC9D8933}.Debug|x64.Build.0 = Debug|x64
|
||||
{828318A8-9B90-4A5F-BD6B-E632CC9D8933}.Release|x64.ActiveCfg = Release|x64
|
||||
{828318A8-9B90-4A5F-BD6B-E632CC9D8933}.Release|x64.Build.0 = Release|x64
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Debug|x64.Build.0 = Debug|x64
|
||||
{53397641-35CA-4336-8E22-2CE12EF476AC}.Release|x64.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace Netch.Controllers
|
||||
{
|
||||
public class DNSController : IController
|
||||
{
|
||||
|
||||
public string Name { get; } = "DNS Service";
|
||||
|
||||
/// <summary>
|
||||
@@ -15,13 +14,14 @@ namespace Netch.Controllers
|
||||
/// <returns></returns>
|
||||
public bool Start()
|
||||
{
|
||||
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath("bin\\china_site_list")),
|
||||
Encoding.UTF8.GetBytes("223.5.5.5:53"),
|
||||
Encoding.UTF8.GetBytes("1.1.1.1:53"))
|
||||
)
|
||||
return false;
|
||||
return
|
||||
aiodns_init();
|
||||
aiodns_dial((int) NameList.TYPE_REST, null);
|
||||
aiodns_dial((int) NameList.TYPE_ADDR, Encoding.UTF8.GetBytes($"{Global.Settings.LocalAddress}:53"));
|
||||
aiodns_dial((int) NameList.TYPE_LIST, Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)));
|
||||
aiodns_dial((int) NameList.TYPE_CDNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"));
|
||||
aiodns_dial((int) NameList.TYPE_ODNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"));
|
||||
aiodns_dial((int) NameList.TYPE_METH, Encoding.UTF8.GetBytes(Global.Settings.AioDNS.Protocol));
|
||||
|
||||
return aiodns_init();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
@@ -32,7 +32,7 @@ namespace Netch.Controllers
|
||||
#region NativeMethods
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_dial(byte[] chinacon, byte[] chinadns, byte[] otherdns);
|
||||
public static extern bool aiodns_dial(int name, byte[] value);
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_init();
|
||||
@@ -40,6 +40,16 @@ namespace Netch.Controllers
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void aiodns_free();
|
||||
|
||||
enum NameList : int
|
||||
{
|
||||
TYPE_REST,
|
||||
TYPE_ADDR,
|
||||
TYPE_LIST,
|
||||
TYPE_CDNS,
|
||||
TYPE_ODNS,
|
||||
TYPE_METH
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace Netch.Controllers
|
||||
/// 程序输出的编码,
|
||||
/// 调用于基类的 <see cref="OnOutputDataReceived"/>
|
||||
/// </summary>
|
||||
protected string InstanceOutputEncoding { get; set; } = "gbk";
|
||||
protected Encoding InstanceOutputEncoding { get; set; } = Encoding.GetEncoding("gbk");
|
||||
|
||||
/// <summary>
|
||||
/// 停止进程
|
||||
@@ -93,10 +93,11 @@ namespace Netch.Controllers
|
||||
WorkingDirectory = $"{Global.NetchDir}\\bin",
|
||||
Arguments = argument,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardError = RedirectStd,
|
||||
RedirectStandardInput = RedirectStd,
|
||||
RedirectStandardOutput = RedirectStd,
|
||||
UseShellExecute = !RedirectStd,
|
||||
RedirectStandardOutput = RedirectStd,
|
||||
StandardOutputEncoding = RedirectStd ? InstanceOutputEncoding : null,
|
||||
RedirectStandardError = RedirectStd,
|
||||
StandardErrorEncoding = RedirectStd ? InstanceOutputEncoding : null,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
}
|
||||
};
|
||||
@@ -192,15 +193,13 @@ namespace Netch.Controllers
|
||||
if (e.Data == null)
|
||||
return;
|
||||
|
||||
var info = Encoding.GetEncoding(InstanceOutputEncoding).GetBytes(e.Data);
|
||||
var str = Encoding.UTF8.GetString(info);
|
||||
Write(str);
|
||||
Write(e.Data);
|
||||
// 检查启动
|
||||
if (State == State.Starting)
|
||||
{
|
||||
if (StartedKeywords.Any(s => str.Contains(s)))
|
||||
if (StartedKeywords.Any(s => e.Data.Contains(s)))
|
||||
State = State.Started;
|
||||
else if (StoppedKeywords.Any(s => str.Contains(s)))
|
||||
else if (StoppedKeywords.Any(s => e.Data.Contains(s)))
|
||||
State = State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using WindowsProxy;
|
||||
using Netch.Utils.HttpProxyHandler;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -31,9 +32,28 @@ namespace Netch.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
pPrivoxyController.Start(MainController.ServerController.Server, mode);
|
||||
if (pPrivoxyController.Start(MainController.Server, mode))
|
||||
{
|
||||
Global.Job.AddProcess(pPrivoxyController.Instance);
|
||||
}
|
||||
|
||||
if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions);
|
||||
if (mode.Type == 3)
|
||||
{
|
||||
if (mode.BypassChina)
|
||||
{
|
||||
//启动PAC服务器
|
||||
PACServerHandle.InitPACServer("127.0.0.1");
|
||||
}
|
||||
else
|
||||
{
|
||||
using var service = new ProxyService
|
||||
{
|
||||
Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}",
|
||||
Bypass = IEProxyExceptions
|
||||
};
|
||||
service.Global();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -82,18 +102,36 @@ namespace Netch.Controllers
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Factory.StartNew(pPrivoxyController.Stop),
|
||||
Task.Factory.StartNew(() =>
|
||||
Task.Run(pPrivoxyController.Stop),
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (prevEnabled)
|
||||
using var service = new ProxyService();
|
||||
try
|
||||
{
|
||||
if (prevHTTP != "")
|
||||
NativeMethods.SetGlobal(prevHTTP, prevBypass);
|
||||
if (prevPAC != "")
|
||||
NativeMethods.SetURL(prevPAC);
|
||||
PACServerHandle.Stop();
|
||||
if (prevEnabled)
|
||||
{
|
||||
if (prevHTTP != "")
|
||||
{
|
||||
service.Server = prevHTTP;
|
||||
service.Bypass = prevBypass;
|
||||
service.Global();
|
||||
}
|
||||
if (prevPAC != "")
|
||||
{
|
||||
service.AutoConfigUrl = prevPAC;
|
||||
service.Pac();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
service.Direct();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"{Name} 控制器出错:\n" + e);
|
||||
}
|
||||
else
|
||||
NativeMethods.SetDIRECT();
|
||||
})
|
||||
};
|
||||
Task.WaitAll(tasks);
|
||||
|
||||
@@ -4,8 +4,6 @@ namespace Netch.Controllers
|
||||
{
|
||||
public interface IServerController : IController
|
||||
{
|
||||
public Server Server { get; set; }
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
@@ -18,12 +19,29 @@ namespace Netch.Controllers
|
||||
private set => _serverController = value;
|
||||
}
|
||||
|
||||
public static IServerController UdpServerController
|
||||
{
|
||||
get => _udpServerController ?? _serverController;
|
||||
set => _udpServerController = value;
|
||||
}
|
||||
|
||||
/// TCP or Both Server
|
||||
public static Server Server;
|
||||
|
||||
public static Server UdpServer
|
||||
{
|
||||
get => _udpServer ?? Server;
|
||||
set => _udpServer = value;
|
||||
}
|
||||
|
||||
private static Server _udpServer;
|
||||
public static IModeController ModeController { get; private set; }
|
||||
|
||||
public static bool NttTested;
|
||||
|
||||
private static readonly NTTController NTTController = new NTTController();
|
||||
private static IServerController _serverController;
|
||||
private static IServerController _udpServerController;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
@@ -34,6 +52,7 @@ namespace Netch.Controllers
|
||||
public static async Task<bool> Start(Server server, Mode mode)
|
||||
{
|
||||
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
Server = server;
|
||||
|
||||
if (server is Socks5 && mode.Type == 4)
|
||||
{
|
||||
@@ -64,17 +83,22 @@ namespace Netch.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
if (!await Task.Run(() => StartServer(server, mode, ref _serverController)))
|
||||
if (!ModeHelper.SkipServerController(server, mode))
|
||||
{
|
||||
if (!await Task.Run(() => StartServer(server, mode, ref _serverController)))
|
||||
{
|
||||
throw new StartFailedException();
|
||||
}
|
||||
|
||||
StatusPortInfoText.UpdateShareLan();
|
||||
}
|
||||
|
||||
if (!await StartMode(mode))
|
||||
{
|
||||
throw new StartFailedException();
|
||||
}
|
||||
|
||||
if (!await StartMode(server, mode))
|
||||
{
|
||||
throw new StartFailedException();
|
||||
}
|
||||
|
||||
if (mode.TestNatRequired)
|
||||
if (mode.TestNatRequired())
|
||||
NatTest();
|
||||
|
||||
return true;
|
||||
@@ -122,8 +146,27 @@ namespace Netch.Controllers
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
|
||||
if (controller.Start(in server, mode))
|
||||
{
|
||||
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
|
||||
StatusPortInfoText.ShareLan = controller.LocalAddress == "0.0.0.0";
|
||||
if (controller is Guard guard)
|
||||
{
|
||||
if (guard.Instance != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Global.Job.AddProcess(guard.Instance);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
if (socks5.Auth())
|
||||
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -131,22 +174,36 @@ namespace Netch.Controllers
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<bool> StartMode(Server server, Mode mode)
|
||||
private static async Task<bool> StartMode(Mode mode)
|
||||
{
|
||||
ModeController = ModeHelper.GetModeControllerByType(mode.Type, out var port, out var portName, out var portType);
|
||||
|
||||
if (ModeController == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (port != null)
|
||||
{
|
||||
PortCheckAndShowMessageBox((ushort) port, portName, portType);
|
||||
UsingPorts.Add((ushort) port);
|
||||
}
|
||||
|
||||
if (ModeController != null)
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
if (await Task.Run(() => ModeController.Start(mode)))
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
return await Task.Run(() => ModeController.Start(mode));
|
||||
if (ModeController is Guard guard)
|
||||
{
|
||||
if (guard.Instance != null)
|
||||
{
|
||||
Global.Job.AddProcess(guard.Instance);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,7 +235,7 @@ namespace Netch.Controllers
|
||||
/// <param name="portName">端口用途名称</param>
|
||||
/// <param name="portType"></param>
|
||||
/// <exception cref="PortInUseException"></exception>
|
||||
private static void PortCheckAndShowMessageBox(ushort port, string portName, PortType portType = PortType.Both)
|
||||
public static void PortCheckAndShowMessageBox(ushort port, string portName, PortType portType = PortType.Both)
|
||||
{
|
||||
if (PortInUse(port, portType))
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
using nfapinet;
|
||||
@@ -46,6 +48,98 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
public bool Start(in Mode mode)
|
||||
{
|
||||
if (!CheckDriver())
|
||||
return false;
|
||||
|
||||
#region aio_dial
|
||||
|
||||
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
|
||||
|
||||
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp) MessageBoxX.Show("?");
|
||||
|
||||
//UDP
|
||||
if (Global.Settings.ProcessNoProxyForUdp)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, "false");
|
||||
SetServer(PortType.TCP);
|
||||
}
|
||||
else
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, "true");
|
||||
SetServer(PortType.Both);
|
||||
}
|
||||
|
||||
//TCP
|
||||
if (Global.Settings.ProcessNoProxyForTcp)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, "false");
|
||||
SetServer(PortType.UDP);
|
||||
}
|
||||
else
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
|
||||
SetServer(PortType.Both);
|
||||
}
|
||||
|
||||
if (!CheckRule(mode.FullRule, out var list))
|
||||
{
|
||||
MessageBoxX.Show($"\"{string.Join("", list.Select(s => s + "\n"))}\" does not conform to C++ regular expression syntax");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetName(mode);
|
||||
|
||||
#endregion
|
||||
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
{
|
||||
// 备份并替换系统 DNS
|
||||
_sysDns = DNS.OutboundDNS;
|
||||
if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS))
|
||||
Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8";
|
||||
DNS.OutboundDNS = Global.Settings.ModifiedDNS;
|
||||
}
|
||||
|
||||
return aio_init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="rules"></param>
|
||||
/// <param name="incompatibleRule"></param>
|
||||
/// <returns>No Problem true</returns>
|
||||
public static bool CheckRule(IEnumerable<string> rules, out IEnumerable<string> incompatibleRule)
|
||||
{
|
||||
incompatibleRule = rules.Where(r => !CheckCppRegex(r, false));
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
return !incompatibleRule.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="clear"></param>
|
||||
/// <returns>No Problem true</returns>
|
||||
public static bool CheckCppRegex(string r, bool clear = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.StartsWith("!"))
|
||||
return aio_dial((int) NameList.TYPE_ADDNAME, r.Substring(1));
|
||||
return aio_dial((int) NameList.TYPE_ADDNAME, r);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (clear)
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckDriver()
|
||||
{
|
||||
var binFileVersion = Utils.Utils.GetFileVersion(BinDriver);
|
||||
var systemFileVersion = Utils.Utils.GetFileVersion(SystemDriver);
|
||||
@@ -53,64 +147,107 @@ namespace Netch.Controllers
|
||||
Logging.Info("内置驱动版本: " + binFileVersion);
|
||||
Logging.Info("系统驱动版本: " + systemFileVersion);
|
||||
|
||||
if (!systemFileVersion.Equals(binFileVersion))
|
||||
if (!File.Exists(BinDriver))
|
||||
{
|
||||
Logging.Warning("内置驱动不存在");
|
||||
if (File.Exists(SystemDriver))
|
||||
{
|
||||
Logging.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
Logging.Warning("使用系统驱动");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!InstallDriver())
|
||||
return false;
|
||||
Logging.Error("未安装驱动");
|
||||
return false;
|
||||
}
|
||||
|
||||
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
|
||||
aio_dial((int) NameList.TYPE_FILTERUDP, "true");
|
||||
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
|
||||
|
||||
SetServer(MainController.ServerController, PortType.Both);
|
||||
|
||||
SetName(mode);
|
||||
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
// 备份并替换系统 DNS
|
||||
_sysDns = DNS.OutboundDNS;
|
||||
DNS.OutboundDNS = "1.1.1.1,8.8.8.8";
|
||||
return InstallDriver();
|
||||
}
|
||||
|
||||
return aio_init();
|
||||
}
|
||||
var updateFlag = false;
|
||||
|
||||
private void SetServer(in IServerController controller, in PortType portType)
|
||||
{
|
||||
if (portType == PortType.Both)
|
||||
if (Version.TryParse(binFileVersion, out var binResult) && Version.TryParse(systemFileVersion, out var systemResult))
|
||||
{
|
||||
SetServer(controller, PortType.TCP);
|
||||
SetServer(controller, PortType.UDP);
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = portType == PortType.UDP ? UdpNameListOffset : 0;
|
||||
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
|
||||
if (controller.Server is Socks5 socks5)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
|
||||
aio_dial((int) NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
|
||||
if (binResult.CompareTo(systemResult) > 0)
|
||||
{
|
||||
// Bin greater than Installed
|
||||
updateFlag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Installed greater than Bin
|
||||
if (systemResult.Major != binResult.Major)
|
||||
{
|
||||
// API breaking changes
|
||||
updateFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!systemFileVersion.Equals(binFileVersion))
|
||||
{
|
||||
updateFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!updateFlag) return true;
|
||||
|
||||
Logging.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
return InstallDriver();
|
||||
}
|
||||
|
||||
private void SetServer(in PortType portType)
|
||||
{
|
||||
if (portType == PortType.Both)
|
||||
{
|
||||
SetServer(PortType.TCP);
|
||||
SetServer(PortType.UDP);
|
||||
return;
|
||||
}
|
||||
|
||||
int offset;
|
||||
Server server;
|
||||
IServerController controller;
|
||||
|
||||
if (portType == PortType.UDP)
|
||||
{
|
||||
offset = UdpNameListOffset;
|
||||
server = MainController.UdpServer;
|
||||
controller = MainController.UdpServerController;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
server = MainController.Server;
|
||||
controller = MainController.ServerController;
|
||||
}
|
||||
|
||||
if (server is Socks5 socks5)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{socks5.AutoResolveHostname()}:{socks5.Port}");
|
||||
aio_dial((int) NameList.TYPE_TCPUSER + offset, socks5.Username ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, socks5.Password ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
}
|
||||
else if (server is Shadowsocks shadowsocks && !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS)
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Shadowsocks");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"{shadowsocks.AutoResolveHostname()}:{shadowsocks.Port}");
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, shadowsocks.EncryptMethod ?? string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, shadowsocks.Password ?? string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_TCPTYPE + offset, "Socks5");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST + offset, $"127.0.0.1:{controller.Socks5LocalPort()}");
|
||||
aio_dial((int) NameList.TYPE_TCPUSER + offset, string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPPASS + offset, string.Empty);
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
}
|
||||
|
||||
aio_dial((int) NameList.TYPE_TCPMETH + offset, string.Empty);
|
||||
}
|
||||
|
||||
private void SetName(Mode mode)
|
||||
@@ -118,10 +255,16 @@ namespace Netch.Controllers
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
foreach (var rule in mode.FullRule)
|
||||
{
|
||||
if (rule.StartsWith("!"))
|
||||
{
|
||||
aio_dial((int) NameList.TYPE_BYPNAME, rule.Substring(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, rule);
|
||||
}
|
||||
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, "NTT.exe");
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, @"NTT\.exe");
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
@@ -141,19 +284,19 @@ namespace Netch.Controllers
|
||||
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
private static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_init();
|
||||
private static extern bool aio_init();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_free();
|
||||
private static extern bool aio_free();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong aio_getUP();
|
||||
private static extern ulong aio_getUP();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong aio_getDL();
|
||||
private static extern ulong aio_getDL();
|
||||
|
||||
|
||||
public enum NameList : int
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
|
||||
@@ -7,10 +8,6 @@ namespace Netch.Controllers
|
||||
{
|
||||
public class NTTController : Guard, IController
|
||||
{
|
||||
private string _localEnd;
|
||||
private string _publicEnd;
|
||||
private string _result;
|
||||
private string _bindingTest;
|
||||
public override string Name { get; protected set; } = "NTT";
|
||||
public override string MainFile { get; protected set; } = "NTT.exe";
|
||||
|
||||
@@ -20,7 +17,10 @@ namespace Netch.Controllers
|
||||
/// <returns></returns>
|
||||
public (string, string, string) Start()
|
||||
{
|
||||
_result = _localEnd = _publicEnd = null;
|
||||
string localEnd=null;
|
||||
string publicEnd=null;
|
||||
string result =null;
|
||||
string bindingTest=null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -28,12 +28,50 @@ namespace Netch.Controllers
|
||||
Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
Instance.WaitForExit();
|
||||
if (_bindingTest == "Fail")
|
||||
_result = "UdpBlocked";
|
||||
return (_result, _localEnd, _publicEnd);
|
||||
var output = Instance.StandardOutput.ReadToEnd();
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(Global.NetchDir, $"logging\\{Name}.log"), output);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Warning($"写入 {Name} 日志错误:\n" + e.Message);
|
||||
}
|
||||
|
||||
foreach (var line in output.Split('\n'))
|
||||
{
|
||||
var str = line.Split(':').Select(s => s.Trim()).ToArray();
|
||||
if (str.Length < 2)
|
||||
continue;
|
||||
var key = str[0];
|
||||
var value = str[1];
|
||||
switch (key)
|
||||
{
|
||||
case "Other address is":
|
||||
case "Nat mapping behavior":
|
||||
case "Nat filtering behavior":
|
||||
break;
|
||||
case "Binding test":
|
||||
bindingTest = value;
|
||||
break;
|
||||
case "Local address":
|
||||
localEnd = value;
|
||||
break;
|
||||
case "Mapped address":
|
||||
publicEnd = value;
|
||||
break;
|
||||
case "result":
|
||||
result = value;
|
||||
break;
|
||||
default:
|
||||
result = str.Last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bindingTest == "Fail")
|
||||
result = "UdpBlocked";
|
||||
return (result, localEnd, publicEnd);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -51,41 +89,6 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private new void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrEmpty(e.Data)) return;
|
||||
Logging.Info($"[NTT] {e.Data}");
|
||||
|
||||
var str = e.Data.Split(':').Select(s => s.Trim()).ToArray();
|
||||
if (str.Length < 2)
|
||||
return;
|
||||
var key = str[0];
|
||||
var value = str[1];
|
||||
switch (key)
|
||||
{
|
||||
case "Other address is":
|
||||
case "Nat mapping behavior":
|
||||
case "Nat filtering behavior":
|
||||
break;
|
||||
case "Binding test":
|
||||
_bindingTest = value;
|
||||
break;
|
||||
case "Local address":
|
||||
_localEnd = value;
|
||||
break;
|
||||
case "Mapped address":
|
||||
_publicEnd = value;
|
||||
break;
|
||||
case "result":
|
||||
_result = value;
|
||||
break;
|
||||
default:
|
||||
_result = str.Last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils.HttpProxyHandler;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils;
|
||||
@@ -17,9 +15,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
public class TUNTAPController : Guard, IModeController
|
||||
{
|
||||
private Mode _savedMode = new Mode();
|
||||
private Server _savedServer = new Server();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 服务器 IP 地址
|
||||
/// </summary>
|
||||
@@ -41,11 +37,9 @@ namespace Netch.Controllers
|
||||
|
||||
public bool Start(in Mode mode)
|
||||
{
|
||||
_savedMode = mode;
|
||||
_savedServer = MainController.ServerController.Server;
|
||||
|
||||
var server = MainController.Server;
|
||||
// 查询服务器 IP 地址
|
||||
_serverAddresses = DNS.Lookup(_savedServer.Hostname);
|
||||
_serverAddresses = DNS.Lookup(server.Hostname);
|
||||
|
||||
// 查找出口适配器
|
||||
if (!Utils.Utils.SearchOutboundAdapter())
|
||||
@@ -66,14 +60,16 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
|
||||
SetupRouteTable();
|
||||
SetupRouteTable(mode);
|
||||
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", Name));
|
||||
|
||||
string dns;
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
if (Global.Settings.TUNTAP.DNS.Any())
|
||||
{
|
||||
dns = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
|
||||
dns = DNS.Join(Global.Settings.TUNTAP.DNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -83,13 +79,27 @@ namespace Netch.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
var _ = DNSController.Start();
|
||||
try
|
||||
{
|
||||
MainController.PortCheckAndShowMessageBox(53, "DNS");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DNSController.Start())
|
||||
{
|
||||
Logging.Error("AioDNS 启动失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
dns = "127.0.0.1";
|
||||
}
|
||||
|
||||
var argument = new StringBuilder();
|
||||
if (_savedServer is Socks5 socks5 && !socks5.Auth())
|
||||
argument.Append($"-proxyServer {_serverAddresses}:{_savedServer.Port} ");
|
||||
if (server is Socks5 socks5 && !socks5.Auth())
|
||||
argument.Append($"-proxyServer {server.AutoResolveHostname()}:{server.Port} ");
|
||||
else
|
||||
argument.Append($"-proxyServer 127.0.0.1:{Global.Settings.Socks5LocalPort} ");
|
||||
|
||||
@@ -109,9 +119,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Factory.StartNew(StopInstance),
|
||||
Task.Factory.StartNew(ClearRouteTable),
|
||||
Task.Factory.StartNew(DNSController.Stop)
|
||||
Task.Run(StopInstance),
|
||||
Task.Run(ClearRouteTable),
|
||||
Task.Run(DNSController.Stop)
|
||||
};
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
@@ -124,73 +134,75 @@ namespace Netch.Controllers
|
||||
/// 设置绕行规则
|
||||
/// </summary>
|
||||
/// <returns>是否设置成功</returns>
|
||||
private void SetupRouteTable()
|
||||
private void SetupRouteTable(Mode mode)
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.Translate("SetupBypass"));
|
||||
Logging.Info("设置路由规则");
|
||||
|
||||
#region Rule IPs
|
||||
|
||||
if (_savedMode.Type == 1)
|
||||
switch (mode.Type)
|
||||
{
|
||||
// 代理规则
|
||||
Logging.Info("代理 → 规则 IP");
|
||||
RouteAction(Action.Create, _savedMode.FullRule, RouteType.TUNTAP);
|
||||
case 1:
|
||||
// 代理规则
|
||||
Logging.Info("代理 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.TUNTAP);
|
||||
|
||||
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP,自己记录解析了返回的 IP,仅支持默认检测服务器
|
||||
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
|
||||
{
|
||||
try
|
||||
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP,自己记录解析了返回的 IP,仅支持默认检测服务器
|
||||
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
|
||||
{
|
||||
Logging.Info("代理 → STUN 服务器 IP");
|
||||
RouteAction(Action.Create,
|
||||
new[]
|
||||
{
|
||||
Dns.GetHostAddresses(Global.Settings.STUN_Server)[0],
|
||||
Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0]
|
||||
}.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
try
|
||||
{
|
||||
Logging.Info("代理 → STUN 服务器 IP");
|
||||
RouteAction(Action.Create,
|
||||
new[]
|
||||
{
|
||||
Dns.GetHostAddresses(Global.Settings.STUN_Server)[0],
|
||||
Dns.GetHostAddresses("stunresponse.coldthunder11.com")[0]
|
||||
}.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
Logging.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
if (Global.Settings.TUNTAP.ProxyDNS)
|
||||
{
|
||||
RouteAction(Action.Create,
|
||||
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
Logging.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
RouteAction(Action.Create,
|
||||
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
}
|
||||
else
|
||||
{
|
||||
RouteAction(Action.Create,
|
||||
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RouteAction(Action.Create,
|
||||
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_savedMode.Type == 2)
|
||||
{
|
||||
// 绕过规则
|
||||
|
||||
// 将 TUN/TAP 网卡权重放到最高
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "netsh",
|
||||
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 2:
|
||||
// 绕过规则
|
||||
|
||||
Logging.Info("绕行 → 规则 IP");
|
||||
RouteAction(Action.Create, _savedMode.FullRule, RouteType.Outbound);
|
||||
// 将 TUN/TAP 网卡权重放到最高
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "netsh",
|
||||
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
);
|
||||
|
||||
Logging.Info("绕行 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
|
||||
break;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -202,7 +214,7 @@ namespace Netch.Controllers
|
||||
Logging.Info("绕行 → 全局绕过 IP");
|
||||
RouteAction(Action.Create, Global.Settings.BypassIPs, RouteType.Outbound);
|
||||
|
||||
if (_savedMode.Type == 2)
|
||||
if (mode.Type == 2)
|
||||
{
|
||||
// 绕过规则
|
||||
Logging.Info("代理 → 全局");
|
||||
@@ -226,33 +238,11 @@ namespace Netch.Controllers
|
||||
|
||||
public bool TestFakeDNS()
|
||||
{
|
||||
var exited = false;
|
||||
var helpStr = new StringBuilder();
|
||||
try
|
||||
{
|
||||
void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
exited = true;
|
||||
return;
|
||||
}
|
||||
|
||||
helpStr.Append(e.Data);
|
||||
}
|
||||
|
||||
InitInstance("-h");
|
||||
// Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
while (!exited)
|
||||
{
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
return helpStr.ToString().Contains("-fakeDns");
|
||||
return Instance.StandardError.ReadToEnd().Contains("-fakeDns");
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
@@ -15,14 +16,14 @@ namespace Netch.Controllers
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2020";
|
||||
|
||||
public const string AssemblyVersion = @"1.6.4";
|
||||
public const string AssemblyVersion = @"1.7.0";
|
||||
private const string Suffix = @"";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
public string LatestVersionNumber;
|
||||
public string LatestVersionUrl;
|
||||
public string LatestVersionDownloadUrl;
|
||||
public Release LatestRelease;
|
||||
|
||||
public event EventHandler NewVersionFound;
|
||||
public event EventHandler NewVersionFoundFailed;
|
||||
@@ -38,12 +39,11 @@ namespace Netch.Controllers
|
||||
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
|
||||
|
||||
var releases = JsonConvert.DeserializeObject<List<Release>>(json);
|
||||
var latestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
|
||||
LatestVersionNumber = latestRelease.tag_name;
|
||||
LatestVersionUrl = latestRelease.html_url;
|
||||
LatestVersionDownloadUrl = latestRelease.assets[0].browser_download_url;
|
||||
Logging.Info($"Github 最新发布版本: {latestRelease.tag_name}");
|
||||
if (VersionUtil.CompareVersion(latestRelease.tag_name, Version) > 0)
|
||||
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
|
||||
LatestVersionNumber = LatestRelease.tag_name;
|
||||
LatestVersionUrl = LatestRelease.html_url;
|
||||
Logging.Info($"Github 最新发布版本: {LatestRelease.tag_name}");
|
||||
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
|
||||
{
|
||||
Logging.Info("发现新版本");
|
||||
NewVersionFound?.Invoke(this, new EventArgs());
|
||||
|
||||
16
Netch/Forms/MainForm.Designer.cs
generated
16
Netch/Forms/MainForm.Designer.cs
generated
@@ -87,6 +87,7 @@
|
||||
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl();
|
||||
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MenuStrip.SuspendLayout();
|
||||
this.ConfigurationGroupBox.SuspendLayout();
|
||||
this.configLayoutPanel.SuspendLayout();
|
||||
@@ -196,6 +197,7 @@
|
||||
this.CleanDNSCacheToolStripMenuItem,
|
||||
this.UpdateACLToolStripMenuItem,
|
||||
this.updateACLWithProxyToolStripMenuItem,
|
||||
this.updatePACToolStripMenuItem,
|
||||
this.UninstallServiceToolStripMenuItem,
|
||||
this.UninstallTapDriverToolStripMenuItem});
|
||||
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
@@ -441,6 +443,7 @@
|
||||
this.EditServerPictureBox.Location = new System.Drawing.Point(3, 3);
|
||||
this.EditServerPictureBox.Name = "EditServerPictureBox";
|
||||
this.EditServerPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.EditServerPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.EditServerPictureBox.TabIndex = 7;
|
||||
this.EditServerPictureBox.TabStop = false;
|
||||
this.EditServerPictureBox.Click += new System.EventHandler(this.EditServerPictureBox_Click);
|
||||
@@ -452,6 +455,7 @@
|
||||
this.CopyLinkPictureBox.Location = new System.Drawing.Point(72, 3);
|
||||
this.CopyLinkPictureBox.Name = "CopyLinkPictureBox";
|
||||
this.CopyLinkPictureBox.Size = new System.Drawing.Size(18, 18);
|
||||
this.CopyLinkPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.CopyLinkPictureBox.TabIndex = 14;
|
||||
this.CopyLinkPictureBox.TabStop = false;
|
||||
this.CopyLinkPictureBox.Click += new System.EventHandler(this.CopyLinkPictureBox_Click);
|
||||
@@ -463,6 +467,7 @@
|
||||
this.DeleteServerPictureBox.Location = new System.Drawing.Point(26, 3);
|
||||
this.DeleteServerPictureBox.Name = "DeleteServerPictureBox";
|
||||
this.DeleteServerPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.DeleteServerPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.DeleteServerPictureBox.TabIndex = 8;
|
||||
this.DeleteServerPictureBox.TabStop = false;
|
||||
this.DeleteServerPictureBox.Click += new System.EventHandler(this.DeleteServerPictureBox_Click);
|
||||
@@ -474,6 +479,7 @@
|
||||
this.SpeedPictureBox.Location = new System.Drawing.Point(49, 3);
|
||||
this.SpeedPictureBox.Name = "SpeedPictureBox";
|
||||
this.SpeedPictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.SpeedPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.SpeedPictureBox.TabIndex = 9;
|
||||
this.SpeedPictureBox.TabStop = false;
|
||||
this.SpeedPictureBox.Click += new System.EventHandler(this.SpeedPictureBox_Click);
|
||||
@@ -501,6 +507,7 @@
|
||||
this.EditModePictureBox.Location = new System.Drawing.Point(3, 3);
|
||||
this.EditModePictureBox.Name = "EditModePictureBox";
|
||||
this.EditModePictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.EditModePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.EditModePictureBox.TabIndex = 12;
|
||||
this.EditModePictureBox.TabStop = false;
|
||||
this.EditModePictureBox.Click += new System.EventHandler(this.EditModePictureBox_Click);
|
||||
@@ -512,6 +519,7 @@
|
||||
this.DeleteModePictureBox.Location = new System.Drawing.Point(26, 3);
|
||||
this.DeleteModePictureBox.Name = "DeleteModePictureBox";
|
||||
this.DeleteModePictureBox.Size = new System.Drawing.Size(16, 16);
|
||||
this.DeleteModePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.DeleteModePictureBox.TabIndex = 13;
|
||||
this.DeleteModePictureBox.TabStop = false;
|
||||
this.DeleteModePictureBox.Click += new System.EventHandler(this.DeleteModePictureBox_Click);
|
||||
@@ -691,6 +699,13 @@
|
||||
this.ButtomControlContainerControl.TabStop = false;
|
||||
this.ButtomControlContainerControl.Text = "groupBox1";
|
||||
//
|
||||
// updatePACToolStripMenuItem
|
||||
//
|
||||
this.updatePACToolStripMenuItem.Name = "updatePACToolStripMenuItem";
|
||||
this.updatePACToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
|
||||
this.updatePACToolStripMenuItem.Text = "Update PAC";
|
||||
this.updatePACToolStripMenuItem.Click += new System.EventHandler(this.updatePACToolStripMenuItem_Click);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
@@ -797,5 +812,6 @@
|
||||
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
|
||||
private System.Windows.Forms.ToolStripMenuItem updatePACToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using Netch.Utils.HttpProxyHandler;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -26,8 +31,9 @@ namespace Netch.Forms
|
||||
var texts = Clipboard.GetText();
|
||||
if (!string.IsNullOrWhiteSpace(texts))
|
||||
{
|
||||
Global.Settings.Server.AddRange(ShareLink.ParseText(texts));
|
||||
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", ShareLink.ParseText(texts).Count));
|
||||
var servers = ShareLink.ParseText(texts);
|
||||
Global.Settings.Server.AddRange(servers);
|
||||
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", servers.Count));
|
||||
|
||||
InitServer();
|
||||
Configuration.Save();
|
||||
@@ -98,9 +104,7 @@ namespace Netch.Forms
|
||||
}
|
||||
|
||||
|
||||
private readonly object _serverLock = new object();
|
||||
|
||||
public async Task UpdateServersFromSubscribe()
|
||||
private async Task UpdateServersFromSubscribe()
|
||||
{
|
||||
void DisableItems(bool v)
|
||||
{
|
||||
@@ -124,9 +128,11 @@ namespace Netch.Forms
|
||||
|
||||
StatusText(i18N.Translate("Starting update subscription"));
|
||||
DisableItems(false);
|
||||
var useProxyToUpdateSubscription = Global.Settings.UseProxyToUpdateSubscription;
|
||||
try
|
||||
{
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
string proxyServer = null;
|
||||
if (useProxyToUpdateSubscription)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
@@ -134,40 +140,10 @@ namespace Netch.Forms
|
||||
Type = 5
|
||||
};
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
}
|
||||
|
||||
await Task.WhenAll(Global.Settings.SubscribeLink.Select(async item => await Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = WebUtil.CreateRequest(item.Link);
|
||||
|
||||
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
request.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
|
||||
|
||||
var servers = ShareLink.ParseText(await WebUtil.DownloadStringAsync(request));
|
||||
|
||||
foreach (var server in servers)
|
||||
{
|
||||
server.Group = item.Remark;
|
||||
}
|
||||
|
||||
lock (_serverLock)
|
||||
{
|
||||
Global.Settings.Server.RemoveAll(server => server.Group.Equals(item.Remark));
|
||||
Global.Settings.Server.AddRange(servers);
|
||||
}
|
||||
|
||||
|
||||
NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, servers.Count));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NotifyTip($"{i18N.TranslateFormat("Update servers error from {0}", item.Remark)}\n{e.Message}", info: false);
|
||||
Logging.Error(e.ToString());
|
||||
}
|
||||
})).ToArray());
|
||||
await Subscription.UpdateServersAsync(proxyServer);
|
||||
|
||||
InitServer();
|
||||
Configuration.Save();
|
||||
@@ -179,9 +155,16 @@ namespace Netch.Forms
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
if (useProxyToUpdateSubscription)
|
||||
{
|
||||
await MainController.Stop();
|
||||
try
|
||||
{
|
||||
await MainController.Stop();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
DisableItems(true);
|
||||
@@ -223,7 +206,12 @@ namespace Netch.Forms
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Run(() => DNS.Cache.Clear());
|
||||
await Task.Run(() =>
|
||||
{
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
DNS.Cache.Clear();
|
||||
});
|
||||
|
||||
StatusText(i18N.Translate("DNS cache cleanup succeeded"));
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -244,19 +232,13 @@ namespace Netch.Forms
|
||||
|
||||
private async void UpdateACL(bool useProxy)
|
||||
{
|
||||
void DisableItems(bool v)
|
||||
{
|
||||
UpdateACLToolStripMenuItem.Enabled = updateACLWithProxyToolStripMenuItem.Enabled = v;
|
||||
}
|
||||
|
||||
if (useProxy && ServerComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
DisableItems(false);
|
||||
|
||||
Enabled = false;
|
||||
|
||||
NotifyTip(i18N.Translate("Updating in the background"));
|
||||
try
|
||||
@@ -292,42 +274,71 @@ namespace Netch.Forms
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
DisableItems(true);
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void updatePACToolStripMenuItem_Click(object sender, EventArgs eventArgs)
|
||||
{
|
||||
Enabled = false;
|
||||
|
||||
NotifyTip(i18N.Translate("Updating in the background"));
|
||||
try
|
||||
{
|
||||
var req = WebUtil.CreateRequest(Global.Settings.GFWLIST);
|
||||
|
||||
string gfwlist = Path.Combine(Global.NetchDir, $"bin\\gfwlist");
|
||||
string pac = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
|
||||
|
||||
await WebUtil.DownloadFileAsync(req, gfwlist);
|
||||
|
||||
var gfwContent = File.ReadAllText(gfwlist);
|
||||
List<string> lines = PACUtil.ParseResult(gfwContent);
|
||||
string abpContent = PACUtil.UnGzip(Resources.abp_js);
|
||||
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
|
||||
File.WriteAllText(pac, abpContent, Encoding.UTF8);
|
||||
|
||||
NotifyTip(i18N.Translate("PAC updated successfully"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NotifyTip(i18N.Translate("PAC update failed") + "\n" + e.Message, info: false);
|
||||
Logging.Error("更新 PAC 失败!" + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
State = State.Starting;
|
||||
Enabled = false;
|
||||
StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
|
||||
var result = false;
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (NFController.UninstallDriver())
|
||||
{
|
||||
result = true;
|
||||
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
|
||||
}
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
State = State.Stopped;
|
||||
if (result)
|
||||
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
State = State.Starting;
|
||||
StatusText(i18N.TranslateFormat("Uninstalling {0}", "TUN/TAP driver"));
|
||||
var result = false;
|
||||
Enabled = false;
|
||||
try
|
||||
{
|
||||
await Task.Run(TUNTAP.deltapall);
|
||||
result = true;
|
||||
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -335,9 +346,8 @@ namespace Netch.Forms
|
||||
}
|
||||
finally
|
||||
{
|
||||
State = State.Stopped;
|
||||
if (result)
|
||||
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
|
||||
State = State.Waiting;
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
@@ -35,7 +37,7 @@ namespace Netch.Forms
|
||||
|
||||
private async void NewVersionLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!_updater.LatestVersionDownloadUrl.Contains("Netch"))
|
||||
if (!_updater.LatestRelease.assets.Any())
|
||||
{
|
||||
Utils.Utils.Open(_updater.LatestVersionUrl);
|
||||
return;
|
||||
@@ -44,15 +46,38 @@ namespace Netch.Forms
|
||||
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
NotifyTip(i18N.Translate("Start downloading new version"));
|
||||
var fileName = Path.GetFileName(new Uri(_updater.LatestVersionDownloadUrl).LocalPath);
|
||||
|
||||
var latestVersionDownloadUrl = _updater.LatestRelease.assets[0].browser_download_url;
|
||||
var tagPage = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(_updater.LatestVersionUrl));
|
||||
var match = Regex.Match(tagPage, @"<td .*>(?<sha256>.*)</td>", RegexOptions.Singleline);
|
||||
|
||||
// TODO Replace with regex get basename and sha256
|
||||
var fileName = Path.GetFileName(new Uri(latestVersionDownloadUrl).LocalPath);
|
||||
fileName = fileName.Insert(fileName.LastIndexOf('.'), _updater.LatestVersionNumber);
|
||||
var fileFullPath = Path.Combine(Global.NetchDir, "data", fileName);
|
||||
|
||||
var sha256 = match.Groups["sha256"].Value;
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(fileFullPath))
|
||||
if (File.Exists(fileFullPath))
|
||||
{
|
||||
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(_updater.LatestVersionDownloadUrl), fileFullPath);
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) == sha256)
|
||||
{
|
||||
RunUpdater();
|
||||
return;
|
||||
}
|
||||
|
||||
File.Delete(fileFullPath);
|
||||
}
|
||||
|
||||
// TODO Replace "New Version Found" to Progress bar
|
||||
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(latestVersionDownloadUrl), fileFullPath);
|
||||
|
||||
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
|
||||
{
|
||||
MessageBoxX.Show("The downloaded file has the wrong hash");
|
||||
return;
|
||||
}
|
||||
|
||||
RunUpdater();
|
||||
|
||||
@@ -79,7 +79,8 @@ namespace Netch.Forms
|
||||
private void LoadProfile(int index)
|
||||
{
|
||||
var p = Global.Settings.Profiles[index];
|
||||
ProfileNameText.Text = p.ModeRemark;
|
||||
ProfileNameText.Text = p.ProfileName;
|
||||
ModeComboBox.ResetCompletionList();
|
||||
|
||||
if (p.IsDummy)
|
||||
throw new Exception("Profile not found.");
|
||||
@@ -160,9 +161,6 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset Mode ComboBox Items
|
||||
ModeComboBox.Text = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
LoadProfile(index);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
@@ -35,10 +36,11 @@ namespace Netch.Forms
|
||||
|
||||
// 启动需要禁用的控件
|
||||
UninstallServiceToolStripMenuItem.Enabled =
|
||||
updateACLWithProxyToolStripMenuItem.Enabled =
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
|
||||
UninstallTapDriverToolStripMenuItem.Enabled =
|
||||
ReloadModesToolStripMenuItem.Enabled = enabled;
|
||||
UpdateACLToolStripMenuItem.Enabled =
|
||||
updateACLWithProxyToolStripMenuItem.Enabled =
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
|
||||
UninstallTapDriverToolStripMenuItem.Enabled =
|
||||
ReloadModesToolStripMenuItem.Enabled = enabled;
|
||||
}
|
||||
|
||||
_state = value;
|
||||
@@ -185,12 +187,7 @@ namespace Netch.Forms
|
||||
{
|
||||
private static ushort? _socks5Port;
|
||||
private static ushort? _httpPort;
|
||||
private static bool? _shareLan;
|
||||
|
||||
public static bool ShareLan
|
||||
{
|
||||
set => _shareLan = value;
|
||||
}
|
||||
private static bool _shareLan;
|
||||
|
||||
public static ushort HttpPort
|
||||
{
|
||||
@@ -202,35 +199,34 @@ namespace Netch.Forms
|
||||
set => _socks5Port = value;
|
||||
}
|
||||
|
||||
public static void UpdateShareLan() => _shareLan = Global.Settings.LocalAddress != "127.0.0.1";
|
||||
|
||||
public static string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_socks5Port == null && _httpPort == null)
|
||||
return string.Empty;
|
||||
|
||||
var text = new StringBuilder();
|
||||
if (_shareLan == true)
|
||||
text.Append(i18N.Translate("Allow other Devices to connect") + " ");
|
||||
var strings = new List<string>();
|
||||
|
||||
if (_socks5Port != null)
|
||||
text.Append($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
|
||||
{
|
||||
strings.Add($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
|
||||
}
|
||||
|
||||
if (_httpPort != null)
|
||||
{
|
||||
if (_socks5Port != null)
|
||||
text.Append(" | ");
|
||||
text.Append($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
|
||||
strings.Add($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
|
||||
}
|
||||
|
||||
return $" ({text})";
|
||||
if (!strings.Any())
|
||||
return string.Empty;
|
||||
|
||||
return $" ({(_shareLan ? i18N.Translate("Allow other Devices to connect") + " " : "")}{string.Join(" | ", strings)})";
|
||||
}
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_httpPort = _socks5Port = null;
|
||||
_shareLan = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,14 +283,19 @@ namespace Netch.Forms
|
||||
|
||||
Configuration.Save();
|
||||
|
||||
if (File.Exists("data\\last.json"))
|
||||
File.Delete("data\\last.json");
|
||||
foreach (var file in new[] {"data\\last.json", "data\\privoxy.conf"})
|
||||
{
|
||||
if (File.Exists(file))
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
State = State.Terminating;
|
||||
}
|
||||
|
||||
#region MISC
|
||||
|
||||
private bool _resumeFlag;
|
||||
|
||||
/// <summary>
|
||||
/// 监听电源事件,自动重启Netch服务
|
||||
/// </summary>
|
||||
@@ -298,20 +303,24 @@ namespace Netch.Forms
|
||||
/// <param name="e"></param>
|
||||
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
|
||||
{
|
||||
//不对Netch命令等待状态的电源事件做任何处理
|
||||
if (!State.Equals(State.Waiting))
|
||||
switch (e.Mode)
|
||||
{
|
||||
switch (e.Mode)
|
||||
{
|
||||
case PowerModes.Suspend: //操作系统即将挂起
|
||||
Logging.Info("操作系统即将挂起,自动停止===>" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
|
||||
case PowerModes.Suspend: //操作系统即将挂起
|
||||
if (!IsWaiting)
|
||||
{
|
||||
_resumeFlag = true;
|
||||
Logging.Info("操作系统即将挂起,自动停止");
|
||||
ControlFun();
|
||||
break;
|
||||
case PowerModes.Resume: //操作系统即将从挂起状态继续
|
||||
Logging.Info("操作系统即将从挂起状态继续,自动重启===>" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
|
||||
}
|
||||
break;
|
||||
case PowerModes.Resume: //操作系统即将从挂起状态继续
|
||||
if (_resumeFlag)
|
||||
{
|
||||
_resumeFlag = false;
|
||||
Logging.Info("操作系统即将从挂起状态继续,自动重启");
|
||||
ControlFun();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +343,7 @@ namespace Netch.Forms
|
||||
|
||||
private async void SpeedPictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
State = State.Starting;
|
||||
Enabled = false;
|
||||
StatusText(i18N.Translate("Testing"));
|
||||
try
|
||||
{
|
||||
@@ -342,7 +351,7 @@ namespace Netch.Forms
|
||||
}
|
||||
finally
|
||||
{
|
||||
State = State.Stopped;
|
||||
Enabled = true;
|
||||
StatusText(i18N.Translate("Test done"));
|
||||
Refresh();
|
||||
}
|
||||
@@ -357,21 +366,23 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
switch (selectedMode.Type)
|
||||
var mode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
if (ModifierKeys == Keys.Control)
|
||||
{
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Hide();
|
||||
new Process(selectedMode).ShowDialog();
|
||||
new Process(mode).ShowDialog();
|
||||
Show();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
MessageBoxX.Show($"Current not support editing {selectedMode.TypeToString()} Mode");
|
||||
Utils.Utils.Open(ModeHelper.GetFullPath(mode.RelativePath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +456,7 @@ namespace Netch.Forms
|
||||
if (WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
Visible = true;
|
||||
ShowInTaskbar = true; // 显示在系统任务栏
|
||||
ShowInTaskbar = true; // 显示在系统任务栏
|
||||
WindowState = FormWindowState.Normal; // 还原窗体
|
||||
}
|
||||
|
||||
@@ -462,14 +473,14 @@ namespace Netch.Forms
|
||||
if (WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
Visible = true;
|
||||
ShowInTaskbar = true; //显示在系统任务栏
|
||||
ShowInTaskbar = true; //显示在系统任务栏
|
||||
WindowState = FormWindowState.Normal; //还原窗体
|
||||
}
|
||||
|
||||
Activate();
|
||||
}
|
||||
|
||||
private void NotifyTip(string text, int timeout = 0, bool info = true)
|
||||
public void NotifyTip(string text, int timeout = 0, bool info = true)
|
||||
{
|
||||
// 会阻塞线程 timeout 秒
|
||||
NotifyIcon.ShowBalloonTip(timeout,
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Mode
|
||||
@@ -139,23 +140,28 @@ namespace Netch.Forms.Mode
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
|
||||
{
|
||||
var process = ProcessNameTextBox.Text;
|
||||
|
||||
if (!RuleListBox.Items.Contains(process))
|
||||
{
|
||||
RuleListBox.Items.Add(process);
|
||||
}
|
||||
|
||||
Edited = true;
|
||||
RuleListBox.SelectedIndex = RuleListBox.Items.IndexOf(process);
|
||||
ProcessNameTextBox.Text = string.Empty;
|
||||
}
|
||||
else
|
||||
if (string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please enter an process name (xxx.exe)"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NFController.CheckCppRegex(ProcessNameTextBox.Text))
|
||||
{
|
||||
MessageBoxX.Show("Rule does not conform to C++ regular expression syntax");
|
||||
return;
|
||||
}
|
||||
|
||||
var process = ProcessNameTextBox.Text;
|
||||
|
||||
if (!RuleListBox.Items.Contains(process))
|
||||
{
|
||||
RuleListBox.Items.Add(process);
|
||||
}
|
||||
|
||||
Edited = true;
|
||||
RuleListBox.SelectedIndex = RuleListBox.Items.IndexOf(process);
|
||||
ProcessNameTextBox.Text = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -168,28 +168,37 @@ namespace Netch.Forms
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_checkActions.All(pair => pair.Value.Invoke(pair.Key.Text)))
|
||||
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
|
||||
|
||||
var flag = true;
|
||||
foreach (var pair in _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)))
|
||||
{
|
||||
foreach (var pair in _saveActions)
|
||||
{
|
||||
switch (pair.Key)
|
||||
{
|
||||
case CheckBox c:
|
||||
pair.Value.Invoke(c.Checked);
|
||||
break;
|
||||
default:
|
||||
pair.Value.Invoke(pair.Key.Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.Server.IndexOf(Server) == -1)
|
||||
Global.Settings.Server.Add(Server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Utils.Utils.ChangeControlForeColor(pair.Key, Color.Red);
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var pair in _saveActions)
|
||||
{
|
||||
switch (pair.Key)
|
||||
{
|
||||
case CheckBox c:
|
||||
pair.Value.Invoke(c.Checked);
|
||||
break;
|
||||
default:
|
||||
pair.Value.Invoke(pair.Key.Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.Server.IndexOf(Server) == -1)
|
||||
Global.Settings.Server.Add(Server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
1047
Netch/Forms/SettingForm.Designer.cs
generated
1047
Netch/Forms/SettingForm.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,13 @@
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using TaskScheduler;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -20,8 +21,9 @@ namespace Netch.Forms
|
||||
}
|
||||
|
||||
|
||||
private void SettingForm2_Load(object sender, EventArgs e)
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
|
||||
Task.Run(() => BeginInvoke(new Action(() => UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns)));
|
||||
}
|
||||
|
||||
@@ -30,17 +32,17 @@ namespace Netch.Forms
|
||||
#region General
|
||||
|
||||
BindTextBox<ushort>(Socks5PortTextBox,
|
||||
p => CheckPort("Socks5", p, Global.Settings.Socks5LocalPort),
|
||||
p => p.ToString() != HTTPPortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
|
||||
p => Global.Settings.Socks5LocalPort = p,
|
||||
Global.Settings.Socks5LocalPort);
|
||||
BindTextBox<ushort>(HTTPPortTextBox,
|
||||
p => CheckPort("HTTP", p, Global.Settings.HTTPLocalPort),
|
||||
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
|
||||
p => Global.Settings.HTTPLocalPort = p,
|
||||
Global.Settings.HTTPLocalPort);
|
||||
BindTextBox<ushort>(RedirectorTextBox,
|
||||
s => CheckPort("RedirectorTCP", s, Global.Settings.RedirectorTCPPort),
|
||||
s => Global.Settings.RedirectorTCPPort = s,
|
||||
Global.Settings.HTTPLocalPort);
|
||||
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != HTTPPortTextBox.Text,
|
||||
p => Global.Settings.RedirectorTCPPort = p,
|
||||
Global.Settings.RedirectorTCPPort);
|
||||
BindCheckBox(AllowDevicesCheckBox,
|
||||
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
|
||||
Global.Settings.LocalAddress switch
|
||||
@@ -50,7 +52,6 @@ namespace Netch.Forms
|
||||
_ => false
|
||||
});
|
||||
|
||||
|
||||
BindCheckBox(BootShadowsocksFromDLLCheckBox,
|
||||
c => Global.Settings.BootShadowsocksFromDLL = c,
|
||||
Global.Settings.BootShadowsocksFromDLL);
|
||||
@@ -58,6 +59,14 @@ namespace Netch.Forms
|
||||
c => Global.Settings.ResolveServerHostname = c,
|
||||
Global.Settings.ResolveServerHostname);
|
||||
|
||||
BindRadioBox(ICMPingRadioBtn,
|
||||
c => Global.Settings.ServerTCPing = c,
|
||||
!Global.Settings.ServerTCPing);
|
||||
|
||||
BindRadioBox(TCPingRadioBtn,
|
||||
c => Global.Settings.ServerTCPing = c,
|
||||
Global.Settings.ServerTCPing);
|
||||
|
||||
BindTextBox<int>(ProfileCountTextBox,
|
||||
i => i > -1,
|
||||
i => Global.Settings.ProfileCount = i,
|
||||
@@ -83,13 +92,31 @@ namespace Netch.Forms
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Process Mode
|
||||
|
||||
BindCheckBox(ModifySystemDNSCheckBox,
|
||||
b => Global.Settings.ModifySystemDNS = b,
|
||||
Global.Settings.ModifySystemDNS);
|
||||
|
||||
ModifySystemDNSCheckBox_CheckedChanged(null, null);
|
||||
|
||||
BindTextBox(ModifiedDNSTextBox,
|
||||
s => DNS.TrySplit(s, out _, 2),
|
||||
s => Global.Settings.ModifiedDNS = s,
|
||||
Global.Settings.ModifiedDNS);
|
||||
|
||||
BindCheckBox(RedirectorSSCheckBox,
|
||||
s => Global.Settings.RedirectorSS = s,
|
||||
Global.Settings.RedirectorSS);
|
||||
|
||||
BindCheckBox(NoProxyForUdpCheckBox,
|
||||
s => Global.Settings.ProcessNoProxyForUdp = s,
|
||||
Global.Settings.ProcessNoProxyForUdp);
|
||||
|
||||
BindCheckBox(NoProxyForTcpCheckBox,
|
||||
s => Global.Settings.ProcessNoProxyForTcp = s,
|
||||
Global.Settings.ProcessNoProxyForTcp);
|
||||
|
||||
#endregion
|
||||
|
||||
#region TUN/TAP
|
||||
@@ -111,6 +138,15 @@ namespace Netch.Forms
|
||||
Global.Settings.TUNTAP.UseCustomDNS);
|
||||
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
|
||||
|
||||
BindTextBox(TUNTAPDNSTextBox,
|
||||
s => !UseCustomDNSCheckBox.Checked || DNS.TrySplit(s, out _, 2),
|
||||
s =>
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
Global.Settings.TUNTAP.DNS = DNS.Split(s).ToList();
|
||||
},
|
||||
DNS.Join(Global.Settings.TUNTAP.DNS));
|
||||
|
||||
BindCheckBox(ProxyDNSCheckBox,
|
||||
b => Global.Settings.TUNTAP.ProxyDNS = b,
|
||||
Global.Settings.TUNTAP.ProxyDNS);
|
||||
@@ -139,6 +175,9 @@ namespace Netch.Forms
|
||||
BindCheckBox(TLSAllowInsecureCheckBox,
|
||||
b => Global.Settings.V2RayConfig.AllowInsecure = b,
|
||||
Global.Settings.V2RayConfig.AllowInsecure);
|
||||
BindCheckBox(UseMuxCheckBox,
|
||||
b => Global.Settings.V2RayConfig.UseMux = b,
|
||||
Global.Settings.V2RayConfig.UseMux);
|
||||
|
||||
BindTextBox<int>(mtuTextBox,
|
||||
i => true,
|
||||
@@ -205,6 +244,25 @@ namespace Netch.Forms
|
||||
Global.Settings.UpdateSubscribeatWhenOpened);
|
||||
|
||||
#endregion
|
||||
|
||||
#region AioDNS
|
||||
|
||||
BindTextBox(AioDNSRulePathTextBox,
|
||||
s => true,
|
||||
s => Global.Settings.AioDNS.RulePath = s,
|
||||
Global.Settings.AioDNS.RulePath);
|
||||
|
||||
BindTextBox(ChinaDNSTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.AioDNS.ChinaDNS = s,
|
||||
Global.Settings.AioDNS.ChinaDNS);
|
||||
|
||||
BindTextBox(OtherDNSTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.AioDNS.OtherDNS = s,
|
||||
Global.Settings.AioDNS.OtherDNS);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
@@ -214,12 +272,12 @@ namespace Netch.Forms
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
|
||||
? Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}")
|
||||
? DNS.Join(Global.Settings.TUNTAP.DNS)
|
||||
: "1.1.1.1";
|
||||
}
|
||||
else
|
||||
{
|
||||
TUNTAPDNSTextBox.Text = "Local DNS";
|
||||
TUNTAPDNSTextBox.Text = "AioDNS";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,77 +306,54 @@ namespace Netch.Forms
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!_checkActions.All(pair => pair.Value.Invoke(pair.Key.Text)))
|
||||
return;
|
||||
Utils.Utils.ComponentIterator(this, component => Utils.Utils.ChangeControlForeColor(component, Color.Black));
|
||||
|
||||
#region Check
|
||||
|
||||
#region TUNTAP
|
||||
|
||||
var dns = new string[0];
|
||||
try
|
||||
var flag = true;
|
||||
foreach (var pair in _checkActions.Where(pair => !pair.Value.Invoke(pair.Key.Text)))
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
dns = TUNTAPDNSTextBox.Text.Split(',').Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim())
|
||||
.ToArray();
|
||||
if (dns.Any())
|
||||
{
|
||||
foreach (var ip in dns)
|
||||
IPAddress.Parse(ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show("DNS can not be empty");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Utils.Utils.ChangeControlForeColor(pair.Key, Color.Red);
|
||||
flag = false;
|
||||
}
|
||||
catch (Exception exception)
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
if (exception is FormatException)
|
||||
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
|
||||
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Behavior
|
||||
#region CheckSTUN
|
||||
|
||||
// STUN
|
||||
string stunServer;
|
||||
int stunServerPort;
|
||||
try
|
||||
var errFlag = false;
|
||||
var stunServer = string.Empty;
|
||||
ushort stunServerPort = 3478;
|
||||
|
||||
var stun = STUN_ServerComboBox.Text.Split(':');
|
||||
|
||||
if (stun.Any())
|
||||
{
|
||||
var stun = STUN_ServerComboBox.Text.Split(':');
|
||||
stunServer = stun[0];
|
||||
|
||||
stunServerPort = 3478;
|
||||
if (stun.Length > 1)
|
||||
stunServerPort = int.Parse(stun[1]);
|
||||
|
||||
if (stunServerPort <= 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
if (!ushort.TryParse(stun[1], out stunServerPort))
|
||||
{
|
||||
errFlag = true;
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("STUN_ServerPort value illegal. Try again."));
|
||||
errFlag = true;
|
||||
}
|
||||
|
||||
if (errFlag)
|
||||
{
|
||||
Utils.Utils.ChangeControlForeColor(STUN_ServerComboBox, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
|
||||
foreach (var pair in _saveActions)
|
||||
@@ -326,73 +361,19 @@ namespace Netch.Forms
|
||||
pair.Value.Invoke(pair.Key);
|
||||
}
|
||||
|
||||
Global.Settings.TUNTAP.DNS = dns.ToList();
|
||||
Global.Settings.STUN_Server = stunServer;
|
||||
Global.Settings.STUN_Server_Port = stunServerPort;
|
||||
Global.Settings.Language = LanguageComboBox.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Register Startup Item
|
||||
|
||||
var scheduler = new TaskSchedulerClass();
|
||||
scheduler.Connect();
|
||||
var folder = scheduler.GetFolder("\\");
|
||||
|
||||
var taskIsExists = false;
|
||||
try
|
||||
{
|
||||
folder.GetTask("Netch Startup");
|
||||
taskIsExists = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (Global.Settings.RunAtStartup)
|
||||
{
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
|
||||
var task = scheduler.NewTask(0);
|
||||
task.RegistrationInfo.Author = "Netch";
|
||||
task.RegistrationInfo.Description = "Netch run at startup.";
|
||||
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
|
||||
|
||||
task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
|
||||
var action = (IExecAction) task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
|
||||
action.Path = Application.ExecutablePath;
|
||||
|
||||
|
||||
task.Settings.ExecutionTimeLimit = "PT0S";
|
||||
task.Settings.DisallowStartIfOnBatteries = false;
|
||||
task.Settings.RunOnlyIfIdle = false;
|
||||
|
||||
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null,
|
||||
_TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
Utils.Utils.RegisterNetchStartupItem();
|
||||
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
|
||||
private bool CheckPort(string portName, ushort port, ushort originPort, PortType portType = PortType.Both)
|
||||
{
|
||||
if (port == originPort) return true;
|
||||
if (!PortHelper.PortInUse(port, portType)) return true;
|
||||
|
||||
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void ICSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -448,11 +429,42 @@ namespace Netch.Forms
|
||||
{
|
||||
control.Checked = value;
|
||||
_checkActions.Add(control, s => true);
|
||||
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
|
||||
_saveActions.Add(control, c => save.Invoke(((CheckBox)c).Checked));
|
||||
}
|
||||
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
|
||||
{
|
||||
control.Checked = value;
|
||||
_checkActions.Add(control, s => true);
|
||||
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
|
||||
}
|
||||
|
||||
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
|
||||
|
||||
private readonly Dictionary<Control, Action<Control>> _saveActions = new Dictionary<Control, Action<Control>>();
|
||||
|
||||
private void ModifySystemDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ModifiedDNSTextBox.Enabled = ModifySystemDNSCheckBox.Checked;
|
||||
}
|
||||
|
||||
private void NoProxyForUdpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (NoProxyForUdpCheckBox.Checked) NoProxyForTcpCheckBox.Checked = false;
|
||||
}
|
||||
|
||||
private void NoProxyForTcpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (NoProxyForTcpCheckBox.Checked) NoProxyForUdpCheckBox.Checked = false;
|
||||
}
|
||||
|
||||
private void ICMPingRadioBtn_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ICMPingRadioBtn.Checked) TCPingRadioBtn.Checked = false;
|
||||
}
|
||||
|
||||
private void TCPingRadioBtn_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (TCPingRadioBtn.Checked) ICMPingRadioBtn.Checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,14 +109,14 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
|
||||
{
|
||||
MessageBoxX.Show("Remark Name Duplicate!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_editingIndex == -1)
|
||||
{
|
||||
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
|
||||
{
|
||||
MessageBoxX.Show("Remark Name Duplicate!");
|
||||
return;
|
||||
}
|
||||
|
||||
Global.Settings.SubscribeLink.Add(new SubscribeLink
|
||||
{
|
||||
Remark = RemarkTextBox.Text,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using WindowsJobAPI;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
@@ -87,5 +87,10 @@ namespace Netch
|
||||
/// 用于存储模式
|
||||
/// </summary>
|
||||
public static readonly List<Mode> Modes = new List<Mode>();
|
||||
|
||||
/// <summary>
|
||||
/// Windows Job API
|
||||
/// </summary>
|
||||
public static readonly JobObject Job = new JobObject();
|
||||
}
|
||||
}
|
||||
@@ -33,20 +33,6 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public int Type = 0;
|
||||
|
||||
public bool SupportSocks5Auth => Type switch
|
||||
{
|
||||
0 => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
public bool TestNatRequired => Type switch
|
||||
{
|
||||
0 => true,
|
||||
1 => true,
|
||||
2 => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 绕过中国(0. 不绕过 1. 绕过)
|
||||
/// </summary>
|
||||
@@ -131,44 +117,15 @@ namespace Netch.Models
|
||||
/// <returns>模式文件字符串</returns>
|
||||
public string ToFileString()
|
||||
{
|
||||
string fileString;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case 0:
|
||||
// 进程模式
|
||||
fileString = $"# {Remark}";
|
||||
break;
|
||||
case 1:
|
||||
// TUN/TAP 规则内 IP CIDR,无 Bypass China 设置
|
||||
fileString = $"# {Remark}, {Type}, 0";
|
||||
break;
|
||||
default:
|
||||
fileString = $"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}";
|
||||
break;
|
||||
}
|
||||
|
||||
fileString += Global.EOF;
|
||||
|
||||
fileString = Rule.Aggregate(fileString, (current, item) => $"{current}{item}{Global.EOF}");
|
||||
// 去除最后的行尾符
|
||||
fileString = fileString.Substring(0, fileString.Length - 2);
|
||||
|
||||
return fileString;
|
||||
}
|
||||
|
||||
public string TypeToString()
|
||||
{
|
||||
return Type switch
|
||||
{
|
||||
0 => "Process",
|
||||
1 => "TUNTAP",
|
||||
2 => "TUNTAP",
|
||||
3 => "SYSTEM",
|
||||
4 => "S5",
|
||||
5 => "S5+HTTP",
|
||||
_ => "ERROR",
|
||||
};
|
||||
return $"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}{Global.EOF}{string.Join(Global.EOF, Rule)}";
|
||||
}
|
||||
}
|
||||
public static class ModeExtension
|
||||
{
|
||||
/// 是否会转发 UDP
|
||||
public static bool TestNatRequired(this Mode mode) => mode.Type is 0 or 1 or 2;
|
||||
|
||||
/// Socks5 分流是否能被有效实施
|
||||
public static bool ClientRouting(this Mode mode) => mode.Type is not (1 or 2);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class Server
|
||||
public class Server : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// 备注
|
||||
@@ -47,14 +47,17 @@ namespace Netch.Models
|
||||
/// <returns>备注</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Remark))
|
||||
{
|
||||
Remark = $"{Hostname}:{Port}";
|
||||
}
|
||||
var remark = string.IsNullOrWhiteSpace(Remark) ? $"{Hostname}:{Port}" : Remark;
|
||||
|
||||
Group = Group.Equals("None") || Group.Equals("") ? "NONE" : Group;
|
||||
if (Group.Equals("None") || Group.Equals(""))
|
||||
Group = "NONE";
|
||||
|
||||
return $"[{ServerHelper.GetUtilByTypeName(Type)?.ShortName ?? "WTF"}][{Group}] {Remark}";
|
||||
return $"[{ServerHelper.GetUtilByTypeName(Type)?.ShortName ?? "WTF"}][{Group}] {remark}";
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return MemberwiseClone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +81,7 @@ namespace Netch.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
return await Utils.Utils.TCPingAsync(destination, Port);
|
||||
return Global.Settings.ServerTCPing ? await Utils.Utils.TCPingAsync(destination, Port) : await Utils.Utils.ICMPing(destination, Port);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -65,6 +67,19 @@ namespace Netch.Models
|
||||
public bool AllowInsecure = true;
|
||||
|
||||
public KcpConfig KcpConfig = new KcpConfig();
|
||||
|
||||
public bool UseMux = false;
|
||||
}
|
||||
|
||||
public class AioDNSConfig
|
||||
{
|
||||
public string RulePath = "bin\\china_site_list";
|
||||
|
||||
public string ChinaDNS = "223.5.5.5";
|
||||
|
||||
public string OtherDNS = "1.1.1.1";
|
||||
|
||||
public string Protocol = "tcp";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,6 +87,11 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public class Setting
|
||||
{
|
||||
|
||||
public V2rayConfig V2RayConfig = new V2rayConfig();
|
||||
|
||||
public AioDNSConfig AioDNS = new AioDNSConfig();
|
||||
|
||||
/// <summary>
|
||||
/// 服务器选择位置
|
||||
/// </summary>
|
||||
@@ -127,6 +147,11 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public bool ModifySystemDNS = false;
|
||||
|
||||
/// <summary>
|
||||
/// 要修改为的系统 DNS
|
||||
/// </summary>
|
||||
public string ModifiedDNS = "1.1.1.1,8.8.8.8";
|
||||
|
||||
/// <summary>
|
||||
/// 解析服务器主机名
|
||||
/// </summary>
|
||||
@@ -137,6 +162,16 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public int RequestTimeout = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// PAC URL
|
||||
/// </summary>
|
||||
public string Pac_Url = "";
|
||||
|
||||
/// <summary>
|
||||
/// PAC端口
|
||||
/// </summary>
|
||||
public int Pac_Port = 2803;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 本地端口
|
||||
/// </summary>
|
||||
@@ -222,6 +257,11 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public string ACL = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
|
||||
|
||||
/// <summary>
|
||||
/// GFWList
|
||||
/// </summary>
|
||||
public string GFWLIST = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用DLL启动Shadowsocks
|
||||
/// </summary>
|
||||
@@ -232,6 +272,24 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public string Language = "System";
|
||||
|
||||
public V2rayConfig V2RayConfig = new V2rayConfig();
|
||||
/// <summary>
|
||||
/// 服务器测试方式 false.ICMPing true.TCPing
|
||||
/// </summary>
|
||||
public bool ServerTCPing = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用RDR内置SS
|
||||
/// </summary>
|
||||
public bool RedirectorSS = false;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理UDP
|
||||
/// </summary>
|
||||
public bool ProcessNoProxyForUdp = false;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public bool ProcessNoProxyForTcp = false;
|
||||
}
|
||||
}
|
||||
@@ -28,30 +28,6 @@ namespace Netch
|
||||
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
|
||||
public static extern bool DeleteRoute(string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 设置直连
|
||||
/// </summary>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool SetDIRECT();
|
||||
|
||||
/// <summary>
|
||||
/// 设置全局
|
||||
/// </summary>
|
||||
/// <param name="remote">地址</param>
|
||||
/// <param name="bypass">绕过</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool SetGlobal([MarshalAs(UnmanagedType.LPTStr)] string remote, [MarshalAs(UnmanagedType.LPTStr)] string bypass);
|
||||
|
||||
/// <summary>
|
||||
/// 设置自动代理
|
||||
/// </summary>
|
||||
/// <param name="remote">URL</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool SetURL([MarshalAs(UnmanagedType.LPTStr)] string remote);
|
||||
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint FlushDNSResolverCache();
|
||||
|
||||
|
||||
@@ -20,8 +20,10 @@ namespace Netch
|
||||
{
|
||||
if (args.Contains("-console"))
|
||||
{
|
||||
NativeMethods.AllocConsole();
|
||||
NativeMethods.AttachConsole(-1);
|
||||
if (!NativeMethods.AttachConsole(-1))
|
||||
{
|
||||
NativeMethods.AllocConsole();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建互斥体防止多次运行
|
||||
|
||||
@@ -66,12 +66,14 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ILMerge" Version="3.0.41" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="3.3.0" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.61" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.62" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0-rc.2.20475.5" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
|
||||
<PackageReference Include="WindowsAPICodePack-Shell" Version="1.1.1" />
|
||||
<PackageReference Include="WindowsJobAPI" Version="5.0.1" />
|
||||
<PackageReference Include="WindowsProxy" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
10
Netch/Properties/Resources.Designer.cs
generated
10
Netch/Properties/Resources.Designer.cs
generated
@@ -60,6 +60,16 @@ namespace Netch.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] abp_js {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("abp_js", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,145 +1,172 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms"
|
||||
name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
|
||||
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</data>
|
||||
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\abp.js.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b03f5f7f11d50a3a
|
||||
</value>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
Netch/Resources/abp.js.gz
Normal file
BIN
Netch/Resources/abp.js.gz
Normal file
Binary file not shown.
@@ -81,10 +81,16 @@
|
||||
"Modes have been reload": "模式已重载",
|
||||
"Clean DNS Cache": "清理 DNS 缓存",
|
||||
"DNS cache cleanup succeeded": "DNS 缓存清理成功",
|
||||
|
||||
"Update PAC": "更新 PAC",
|
||||
"PAC updated successfully": "PAC 更新成功",
|
||||
"PAC update failed": "PAC 更新失败",
|
||||
|
||||
"Update ACL": "更新 ACL 规则",
|
||||
"Update ACL with proxy": "使用代理更新 ACL 规则",
|
||||
"ACL updated successfully": "ACL 更新成功",
|
||||
"ACL update failed": "ACL 更新失败",
|
||||
|
||||
"Open Directory": "打开目录",
|
||||
|
||||
"About": "关于",
|
||||
@@ -155,6 +161,8 @@
|
||||
"Update subscribeat when opened": "自动更新订阅",
|
||||
"SS DLL": "SS DLL",
|
||||
"Modify System DNS": "修改系统 DNS",
|
||||
"No Proxy for Udp": "不代理Udp流量",
|
||||
"No Proxy for Tcp": "不代理Tcp流量",
|
||||
"ProfileCount": "快捷配置数量",
|
||||
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",
|
||||
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试。",
|
||||
@@ -163,6 +171,7 @@
|
||||
"Failed to set the system proxy, it may be caused by the lack of dependent programs. Do you want to jump to Netch's official website to download dependent programs?": "设置系统代理失败,可能是缺少依赖导致,是否跳转 Netch 官网下载依赖程序?",
|
||||
"Delay test after start": "启动后延迟测试",
|
||||
"Enable": "启用",
|
||||
"ServerPingType": "测速方式",
|
||||
"Detection interval(sec)": "检测间隔(秒)",
|
||||
"STUN Server": "STUN 服务器",
|
||||
"STUN Server Port": "STUN 服务器端口",
|
||||
|
||||
@@ -11,18 +11,17 @@ namespace Netch.Servers.Shadowsocks
|
||||
public override string Name { get; protected set; } = "Shadowsocks";
|
||||
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
|
||||
|
||||
public Server Server { get; set; }
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
private Mode _savedMode;
|
||||
public bool DllFlag => Global.Settings.BootShadowsocksFromDLL && (_savedMode.Type == 0 || _savedMode.Type == 1 || _savedMode.Type == 2);
|
||||
public bool DllFlag;
|
||||
|
||||
public bool Start(in Server s, in Mode mode)
|
||||
{
|
||||
_savedMode = mode;
|
||||
Server = s;
|
||||
var server = (Shadowsocks) s;
|
||||
|
||||
DllFlag = Global.Settings.BootShadowsocksFromDLL && mode.Type is 0 or 1 or 2 && !server.HasPlugin();
|
||||
|
||||
//从DLL启动Shaowsocks
|
||||
if (DllFlag)
|
||||
{
|
||||
@@ -76,14 +75,12 @@ namespace Netch.Servers.Shadowsocks
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
if (Instance == null)
|
||||
if (DllFlag)
|
||||
ShadowsocksDLL.Stop();
|
||||
else
|
||||
StopInstance();
|
||||
_savedMode = null;
|
||||
}
|
||||
|
||||
|
||||
private class ShadowsocksDLL
|
||||
{
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
Type = "SS";
|
||||
}
|
||||
|
||||
public bool HasPlugin() => !string.IsNullOrWhiteSpace(Plugin) && !string.IsNullOrWhiteSpace(PluginOption);
|
||||
}
|
||||
|
||||
public static class SSGlobal
|
||||
|
||||
@@ -11,13 +11,11 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
public override string Name { get; protected set; } = "ShadowsocksR";
|
||||
|
||||
public Server Server { get; set; }
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
public bool Start(in Server s, in Mode mode)
|
||||
{
|
||||
Server = s;
|
||||
var server = (ShadowsocksR) s;
|
||||
|
||||
#region Argument
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.ShadowsocksR.Form;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -100,6 +101,22 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
var group = paramsDict.ContainsKey("group") ? ShareLink.URLSafeBase64Decode(paramsDict["group"]) : string.Empty;
|
||||
|
||||
if (SSGlobal.EncryptMethods.Contains(method) && protocol == "origin" && obfs == "plain")
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new Shadowsocks.Shadowsocks
|
||||
{
|
||||
Hostname = serverAddr,
|
||||
Port = serverPort,
|
||||
EncryptMethod = method,
|
||||
Password = password,
|
||||
Remark = remarks,
|
||||
Group = group
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new[]
|
||||
{
|
||||
new ShadowsocksR
|
||||
|
||||
@@ -12,9 +12,8 @@ namespace Netch.Servers.Socks5
|
||||
|
||||
public bool Start(in Server s, in Mode mode)
|
||||
{
|
||||
Server = s;
|
||||
var server = (Socks5) s;
|
||||
if (server.Auth() && !mode.SupportSocks5Auth)
|
||||
if (server.Auth())
|
||||
{
|
||||
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
|
||||
if (StartInstanceAuto("-config ..\\data\\last.json"))
|
||||
@@ -34,7 +33,6 @@ namespace Netch.Servers.Socks5
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
public Server Server { get; set; }
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
@@ -18,27 +18,32 @@ namespace Netch.Servers.Trojan
|
||||
|
||||
public override string MainFile { get; protected set; } = "Trojan.exe";
|
||||
public override string Name { get; protected set; } = "Trojan";
|
||||
public Server Server { get; set; }
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
|
||||
public bool Start(in Server s, in Mode mode)
|
||||
{
|
||||
Server = s;
|
||||
var server = (Trojan) s;
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new TrojanConfig
|
||||
var trojanConfig = new TrojanConfig
|
||||
{
|
||||
local_addr = this.LocalAddress(),
|
||||
local_port = this.Socks5LocalPort(),
|
||||
remote_addr = server.AutoResolveHostname(),
|
||||
remote_addr = server.Hostname,
|
||||
remote_port = server.Port,
|
||||
password = new List<string>
|
||||
{
|
||||
server.Password
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(server.Host))
|
||||
trojanConfig.ssl.sni = server.Host;
|
||||
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(trojanConfig, Formatting.Indented, new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}));
|
||||
return StartInstanceAuto("-c ..\\data\\last.json");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,17 @@ namespace Netch.Servers.VLESS
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public new string EncryptMethod { get; set; } = "none";
|
||||
public override string EncryptMethod { get; set; } = "none";
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议
|
||||
/// </summary>
|
||||
public new string TransferProtocol { get; set; } = VLESSGlobal.TransferProtocols[0];
|
||||
public override string TransferProtocol { get; set; } = VLESSGlobal.TransferProtocols[0];
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public new string FakeType { get; set; } = VLESSGlobal.FakeTypes[0];
|
||||
public override string FakeType { get; set; } = VLESSGlobal.FakeTypes[0];
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -34,7 +34,6 @@ namespace Netch.Servers.VLESS
|
||||
|
||||
public class VLESSGlobal
|
||||
{
|
||||
|
||||
public static List<string> TransferProtocols => VMessGlobal.TransferProtocols;
|
||||
|
||||
public static readonly List<string> FakeTypes = new List<string>
|
||||
@@ -42,5 +41,12 @@ namespace Netch.Servers.VLESS
|
||||
"none",
|
||||
"http"
|
||||
};
|
||||
|
||||
public static readonly List<string> TLSSecure = new List<string>
|
||||
{
|
||||
"",
|
||||
"tls",
|
||||
"xtls"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,12 @@ namespace Netch.Servers.VLESS
|
||||
public override string Name { get; protected set; } = "VLESS";
|
||||
public override string MainFile { get; protected set; } = "v2ray.exe";
|
||||
|
||||
public Server Server { get; set; }
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
public bool Start(in Server s,in Mode mode)
|
||||
{
|
||||
Server = s;
|
||||
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
|
||||
return StartInstanceAuto("-config ..\\data\\last.json");
|
||||
}
|
||||
|
||||
@@ -39,22 +39,20 @@ namespace Netch.Servers.VLESS.VLESSForm
|
||||
s => true,
|
||||
s => server.Path = s,
|
||||
server.Path);
|
||||
CreateComboBox("TLSSecure", "TLS Secure",
|
||||
CreateComboBox("UseMux", "Use Mux",
|
||||
new List<string> {"", "true", "false"},
|
||||
s =>
|
||||
s => server.UseMux = s switch
|
||||
{
|
||||
server.TLSSecure = s switch
|
||||
{
|
||||
"" => null,
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => null
|
||||
};
|
||||
"" => null,
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => null
|
||||
},
|
||||
server.TLSSecure?.ToString() ?? string.Empty);
|
||||
CreateCheckBox("UseMux", "Use Mux",
|
||||
b => server.UseMux = b,
|
||||
server.UseMux);
|
||||
server.UseMux?.ToString().ToLower() ?? "");
|
||||
CreateComboBox("TLSSecure", "TLS Secure",
|
||||
VLESSGlobal.TLSSecure,
|
||||
s => server.TLSSecureType = s,
|
||||
server.TLSSecureType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,22 +48,20 @@ namespace Netch.Servers.VMess.Form
|
||||
s => true,
|
||||
s => server.QUICSecret = s,
|
||||
server.QUICSecret);
|
||||
CreateComboBox("TLSSecure", "TLS Secure",
|
||||
CreateComboBox("UseMux", "Use Mux",
|
||||
new List<string> {"", "true", "false"},
|
||||
s =>
|
||||
s => server.UseMux = s switch
|
||||
{
|
||||
server.TLSSecure = s switch
|
||||
{
|
||||
"" => null,
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => null
|
||||
};
|
||||
"" => null,
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => null
|
||||
},
|
||||
server.TLSSecure?.ToString() ?? string.Empty);
|
||||
CreateCheckBox("UseMux", "Use Mux",
|
||||
s => server.UseMux = s,
|
||||
server.UseMux);
|
||||
server.UseMux?.ToString().ToLower() ?? "");
|
||||
CreateComboBox("TLSSecure", "TLS Secure",
|
||||
VMessGlobal.TLSSecure,
|
||||
s => server.TLSSecureType = s,
|
||||
server.TLSSecureType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,8 +195,6 @@ namespace Netch.Servers.VMess.Models
|
||||
|
||||
public class TcpSettings
|
||||
{
|
||||
public bool connectionReuse { get; set; }
|
||||
|
||||
public Header header { get; set; }
|
||||
}
|
||||
|
||||
@@ -257,8 +255,6 @@ namespace Netch.Servers.VMess.Models
|
||||
|
||||
public class WsSettings
|
||||
{
|
||||
public bool connectionReuse { get; set; }
|
||||
|
||||
public string path { get; set; }
|
||||
|
||||
public Headers headers { get; set; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.VMess.Models;
|
||||
using Newtonsoft.Json;
|
||||
@@ -18,9 +19,9 @@ namespace Netch.Servers.VMess.Utils
|
||||
|
||||
routing(server, mode, ref v2rayConfig);
|
||||
|
||||
outbound(server, ref v2rayConfig);
|
||||
outbound(server, mode, ref v2rayConfig);
|
||||
|
||||
return JsonConvert.SerializeObject(v2rayConfig);
|
||||
return JsonConvert.SerializeObject(v2rayConfig, Formatting.Indented, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -58,44 +59,72 @@ namespace Netch.Servers.VMess.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
RulesItem rulesItem;
|
||||
var directRuleObject = new RulesItem
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>(),
|
||||
domain = new List<string>(),
|
||||
outboundTag = "direct"
|
||||
};
|
||||
|
||||
var blockRuleObject = new RulesItem
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>(),
|
||||
domain = new List<string>(),
|
||||
outboundTag = "block"
|
||||
};
|
||||
|
||||
if (mode.BypassChina)
|
||||
{
|
||||
rulesItem = new RulesItem
|
||||
switch (mode.Type)
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
{
|
||||
"geoip:cn",
|
||||
"geoip:private"
|
||||
},
|
||||
domain = new List<string>
|
||||
{
|
||||
"geosite:cn"
|
||||
},
|
||||
outboundTag = "direct"
|
||||
};
|
||||
case 0:
|
||||
directRuleObject.ip.Add("geoip:cn");
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (Global.Flags.SupportFakeDns && Global.Settings.TUNTAP.UseFakeDNS)
|
||||
directRuleObject.domain.Add("geosite:cn");
|
||||
else
|
||||
directRuleObject.ip.Add("geoip:cn");
|
||||
break;
|
||||
default:
|
||||
directRuleObject.domain.Add("geosite:cn");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (mode.Type is 0 or 1 or 2)
|
||||
{
|
||||
rulesItem = new RulesItem
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
{
|
||||
"geoip:private"
|
||||
},
|
||||
outboundTag = "direct"
|
||||
};
|
||||
blockRuleObject.ip.Add("geoip:private");
|
||||
}
|
||||
|
||||
v2rayConfig.routing = new Routing
|
||||
{
|
||||
rules = new List<RulesItem>
|
||||
{
|
||||
rulesItem
|
||||
}
|
||||
rules = new List<RulesItem>()
|
||||
};
|
||||
|
||||
static bool CheckRuleItem(ref RulesItem rulesItem)
|
||||
{
|
||||
bool ipResult, domainResult;
|
||||
if (!(ipResult = rulesItem.ip.Any()))
|
||||
{
|
||||
rulesItem.ip = null;
|
||||
}
|
||||
|
||||
if (!(domainResult = rulesItem.domain.Any()))
|
||||
{
|
||||
rulesItem.domain = null;
|
||||
}
|
||||
|
||||
return ipResult || domainResult;
|
||||
}
|
||||
|
||||
if (CheckRuleItem(ref directRuleObject))
|
||||
v2rayConfig.routing.rules.Add(directRuleObject);
|
||||
if (CheckRuleItem(ref blockRuleObject))
|
||||
v2rayConfig.routing.rules.Add(blockRuleObject);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -103,7 +132,7 @@ namespace Netch.Servers.VMess.Utils
|
||||
}
|
||||
}
|
||||
|
||||
private static void outbound(Server server, ref V2rayConfig v2rayConfig)
|
||||
private static void outbound(Server server, Mode mode, ref V2rayConfig v2rayConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -121,31 +150,25 @@ namespace Netch.Servers.VMess.Utils
|
||||
{
|
||||
case Socks5.Socks5 socks5:
|
||||
{
|
||||
var serversItem = new ServersItem
|
||||
{
|
||||
users = new List<SocksUsersItem>()
|
||||
};
|
||||
outbound.settings.servers = new List<ServersItem>
|
||||
{
|
||||
serversItem
|
||||
};
|
||||
|
||||
serversItem.address = server.AutoResolveHostname();
|
||||
serversItem.port = server.Port;
|
||||
serversItem.method = null;
|
||||
serversItem.password = null;
|
||||
|
||||
if (socks5.Auth())
|
||||
{
|
||||
var socksUsersItem = new SocksUsersItem
|
||||
new ServersItem
|
||||
{
|
||||
user = socks5.Username,
|
||||
pass = socks5.Password,
|
||||
level = 1
|
||||
};
|
||||
|
||||
serversItem.users.Add(socksUsersItem);
|
||||
}
|
||||
users = socks5.Auth()
|
||||
? new List<SocksUsersItem>
|
||||
{
|
||||
new SocksUsersItem
|
||||
{
|
||||
user = socks5.Username,
|
||||
pass = socks5.Password,
|
||||
level = 1
|
||||
}
|
||||
}
|
||||
: null,
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
}
|
||||
};
|
||||
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
@@ -156,37 +179,36 @@ namespace Netch.Servers.VMess.Utils
|
||||
{
|
||||
var vnextItem = new VnextItem
|
||||
{
|
||||
users = new List<UsersItem>()
|
||||
users = new List<UsersItem>(),
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
outbound.settings.vnext = new List<VnextItem>
|
||||
outbound.settings.vnext = new List<VnextItem> {vnextItem};
|
||||
|
||||
var usersItem = new UsersItem
|
||||
{
|
||||
vnextItem
|
||||
id = vless.UserID,
|
||||
alterId = 0,
|
||||
flow = string.Empty,
|
||||
encryption = vless.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.address = server.AutoResolveHostname();
|
||||
vnextItem.port = server.Port;
|
||||
|
||||
var usersItem = new UsersItem();
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
usersItem.id = vless.UserID;
|
||||
usersItem.alterId = 0;
|
||||
usersItem.flow = string.Empty;
|
||||
usersItem.encryption = vless.EncryptMethod;
|
||||
|
||||
outbound.mux.enabled = vless.UseMux;
|
||||
outbound.mux.concurrency = vless.UseMux ? 8 : -1;
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
boundStreamSettings(vless, ref streamSettings);
|
||||
|
||||
if (vless.TransferProtocol == "xtls")
|
||||
if (vless.TLSSecureType == "xtls")
|
||||
{
|
||||
usersItem.flow = string.IsNullOrEmpty(vless.Flow) ? "xtls-rprx-origin" : vless.Flow;
|
||||
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
outbound.mux.enabled = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux;
|
||||
outbound.mux.concurrency = vless.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
|
||||
}
|
||||
|
||||
outbound.protocol = "vless";
|
||||
outbound.settings.servers = null;
|
||||
@@ -196,35 +218,42 @@ namespace Netch.Servers.VMess.Utils
|
||||
{
|
||||
var vnextItem = new VnextItem
|
||||
{
|
||||
users = new List<UsersItem>()
|
||||
users = new List<UsersItem>(),
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
outbound.settings.vnext = new List<VnextItem>
|
||||
outbound.settings.vnext = new List<VnextItem> {vnextItem};
|
||||
|
||||
var usersItem = new UsersItem
|
||||
{
|
||||
vnextItem
|
||||
id = vmess.UserID,
|
||||
alterId = vmess.AlterID,
|
||||
security = vmess.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.address = server.AutoResolveHostname();
|
||||
vnextItem.port = server.Port;
|
||||
|
||||
var usersItem = new UsersItem();
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
usersItem.id = vmess.UserID;
|
||||
usersItem.alterId = vmess.AlterID;
|
||||
usersItem.security = vmess.EncryptMethod;
|
||||
|
||||
outbound.mux.enabled = vmess.UseMux;
|
||||
outbound.mux.concurrency = vmess.UseMux ? 8 : -1;
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
boundStreamSettings(vmess, ref streamSettings);
|
||||
|
||||
outbound.mux.enabled = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux;
|
||||
outbound.mux.concurrency = vmess.UseMux ?? Global.Settings.V2RayConfig.UseMux ? 8 : -1;
|
||||
outbound.protocol = "vmess";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v2rayConfig.outbounds = new List<Outbounds> {outbound};
|
||||
v2rayConfig.outbounds = new List<Outbounds>
|
||||
{
|
||||
outbound,
|
||||
new Outbounds
|
||||
{
|
||||
tag = "direct", protocol = "freedom"
|
||||
},
|
||||
new Outbounds
|
||||
{
|
||||
tag = "block", protocol = "blackhole"
|
||||
}
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -237,25 +266,24 @@ namespace Netch.Servers.VMess.Utils
|
||||
try
|
||||
{
|
||||
streamSettings.network = server.TransferProtocol;
|
||||
var host = server.Host;
|
||||
if (server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure)
|
||||
{
|
||||
streamSettings.security = "tls";
|
||||
|
||||
if ((streamSettings.security = server.TLSSecureType) != "")
|
||||
{
|
||||
var tlsSettings = new TlsSettings
|
||||
{
|
||||
allowInsecure = true
|
||||
allowInsecure = Global.Settings.V2RayConfig.AllowInsecure,
|
||||
serverName = !string.IsNullOrWhiteSpace(server.Host) ? server.Host : null
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
tlsSettings.serverName = host;
|
||||
}
|
||||
|
||||
streamSettings.tlsSettings = tlsSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
streamSettings.security = "";
|
||||
switch (server.TLSSecureType)
|
||||
{
|
||||
case "tls":
|
||||
streamSettings.tlsSettings = tlsSettings;
|
||||
break;
|
||||
case "xtls":
|
||||
streamSettings.xtlsSettings = tlsSettings;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (server.TransferProtocol)
|
||||
@@ -277,21 +305,15 @@ namespace Netch.Servers.VMess.Utils
|
||||
seed = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
|
||||
};
|
||||
|
||||
|
||||
streamSettings.kcpSettings = kcpSettings;
|
||||
break;
|
||||
case "ws":
|
||||
var path = server.Path;
|
||||
var wsSettings = new WsSettings
|
||||
{
|
||||
connectionReuse = true,
|
||||
headers = !string.IsNullOrWhiteSpace(host)
|
||||
? new Headers
|
||||
{
|
||||
Host = host
|
||||
}
|
||||
headers = !string.IsNullOrWhiteSpace(server.Host)
|
||||
? new Headers {Host = server.Host}
|
||||
: null,
|
||||
path = !string.IsNullOrWhiteSpace(path) ? path : null
|
||||
path = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
|
||||
};
|
||||
|
||||
streamSettings.wsSettings = wsSettings;
|
||||
@@ -311,40 +333,27 @@ namespace Netch.Servers.VMess.Utils
|
||||
case "quic":
|
||||
var quicSettings = new QuicSettings
|
||||
{
|
||||
security = host,
|
||||
security = server.Host,
|
||||
key = server.Path,
|
||||
header = new Header
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
};
|
||||
if (server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure)
|
||||
|
||||
if (server.TLSSecureType != "")
|
||||
{
|
||||
// tls or xtls
|
||||
streamSettings.tlsSettings.serverName = server.Hostname;
|
||||
}
|
||||
|
||||
streamSettings.quicSettings = quicSettings;
|
||||
break;
|
||||
case "xtls":
|
||||
streamSettings.security = server.TransferProtocol;
|
||||
|
||||
var xtlsSettings = new TlsSettings
|
||||
{
|
||||
allowInsecure = true
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
xtlsSettings.serverName = host;
|
||||
}
|
||||
|
||||
streamSettings.xtlsSettings = xtlsSettings;
|
||||
break;
|
||||
default:
|
||||
if (server.FakeType == "http")
|
||||
{
|
||||
var tcpSettings = new TcpSettings
|
||||
{
|
||||
connectionReuse = true,
|
||||
header = new Header
|
||||
{
|
||||
type = server.FakeType,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
@@ -23,18 +24,18 @@ namespace Netch.Servers.VMess
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod { get; set; } = VMessGlobal.EncryptMethods[0];
|
||||
public virtual string EncryptMethod { get; set; } = VMessGlobal.EncryptMethods[0];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议
|
||||
/// </summary>
|
||||
public string TransferProtocol { get; set; } = VMessGlobal.TransferProtocols[0];
|
||||
public virtual string TransferProtocol { get; set; } = VMessGlobal.TransferProtocols[0];
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public string FakeType { get; set; } = VMessGlobal.FakeTypes[0];
|
||||
public virtual string FakeType { get; set; } = VMessGlobal.FakeTypes[0];
|
||||
|
||||
/// <summary>
|
||||
/// QUIC
|
||||
@@ -64,12 +65,12 @@ namespace Netch.Servers.VMess
|
||||
/// <summary>
|
||||
/// TLS 底层传输安全
|
||||
/// </summary>
|
||||
public bool? TLSSecure { get; set; }
|
||||
public string TLSSecureType { get; set; } = VMessGlobal.TLSSecure[0];
|
||||
|
||||
/// <summary>
|
||||
/// Mux 多路复用
|
||||
/// </summary>
|
||||
public bool UseMux { get; set; } = true;
|
||||
public bool? UseMux { get; set; } = false;
|
||||
}
|
||||
|
||||
public class VMessGlobal
|
||||
@@ -114,5 +115,14 @@ namespace Netch.Servers.VMess
|
||||
"dtls",
|
||||
"wireguard"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// TLS 安全类型
|
||||
/// </summary>
|
||||
public static readonly List<string> TLSSecure = new List<string>
|
||||
{
|
||||
"",
|
||||
"tls"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -13,16 +13,14 @@ namespace Netch.Servers.VMess
|
||||
StoppedKeywords.AddRange(new[] {"config file not readable", "failed to"});
|
||||
}
|
||||
|
||||
public override string Name { get; protected set; } = "V2Ray";
|
||||
public override string Name { get; protected set; } = "VMess";
|
||||
public override string MainFile { get; protected set; } = "v2ray.exe";
|
||||
public Server Server { get; set; }
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
|
||||
public bool Start(in Server s,in Mode mode)
|
||||
{
|
||||
Server = s;
|
||||
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
|
||||
return StartInstanceAuto("-config ..\\data\\last.json");
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Netch.Servers.VMess
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecure ?? Global.Settings.V2RayConfig.AllowInsecure ? "tls" : ""
|
||||
tls = server.TLSSecureType
|
||||
});
|
||||
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
|
||||
}
|
||||
@@ -97,7 +97,7 @@ namespace Netch.Servers.VMess
|
||||
data.Path = vmess.path;
|
||||
}
|
||||
|
||||
data.TLSSecure = vmess.tls == "tls";
|
||||
data.TLSSecureType = vmess.tls;
|
||||
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
|
||||
|
||||
return CheckServer(data) ? new[] {data} : null;
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.Diagnostics.Tracing.Session;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -63,26 +64,28 @@ namespace Netch.Utils
|
||||
|
||||
//var processList = Process.GetProcessesByName(ProcessName).Select(p => p.Id).ToHashSet();
|
||||
var instances = new List<Process>();
|
||||
if (server.Type.Equals("Socks5") && MainController.ModeController.Name == "HTTP")
|
||||
switch (MainController.ServerController)
|
||||
{
|
||||
instances.Add(((HTTPController) MainController.ModeController).pPrivoxyController.Instance);
|
||||
}
|
||||
else if (MainController.ServerController != null)
|
||||
{
|
||||
switch (MainController.ServerController)
|
||||
{
|
||||
case SSController ssController when ssController.DllFlag:
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
break;
|
||||
case Guard instanceController:
|
||||
case null:
|
||||
break;
|
||||
case SSController ssController when ssController.DllFlag:
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
break;
|
||||
case Guard instanceController:
|
||||
if (instanceController.Instance != null)
|
||||
instances.Add(instanceController.Instance);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (MainController.ModeController != null)
|
||||
|
||||
if (!instances.Any())
|
||||
{
|
||||
switch (MainController.ModeController)
|
||||
{
|
||||
case null:
|
||||
break;
|
||||
case HTTPController httpController:
|
||||
instances.Add(httpController.pPrivoxyController.Instance);
|
||||
break;
|
||||
case NFController _:
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
break;
|
||||
|
||||
@@ -30,14 +30,14 @@ namespace Netch.Utils
|
||||
Global.Settings = settingJObject?.ToObject<Setting>() ?? new Setting();
|
||||
Global.Settings.Server.Clear();
|
||||
|
||||
foreach (JObject server in settingJObject["Server"])
|
||||
{
|
||||
var serverResult = ServerHelper.ParseJObject(server);
|
||||
if (serverResult != null)
|
||||
Global.Settings.Server.Add(serverResult);
|
||||
}
|
||||
if (settingJObject?["Server"] != null)
|
||||
foreach (JObject server in settingJObject["Server"])
|
||||
{
|
||||
var serverResult = ServerHelper.ParseJObject(server);
|
||||
if (serverResult != null)
|
||||
Global.Settings.Server.Add(serverResult);
|
||||
}
|
||||
}
|
||||
|
||||
catch (JsonException)
|
||||
{
|
||||
}
|
||||
@@ -62,7 +62,15 @@ namespace Netch.Utils
|
||||
Directory.CreateDirectory(DATA_DIR);
|
||||
}
|
||||
|
||||
File.WriteAllText(SETTINGS_JSON, JsonConvert.SerializeObject(Global.Settings, Formatting.Indented));
|
||||
File.WriteAllText(SETTINGS_JSON,
|
||||
JsonConvert.SerializeObject(
|
||||
Global.Settings,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.Win32;
|
||||
|
||||
@@ -75,5 +77,24 @@ namespace Netch.Utils
|
||||
}
|
||||
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Split(string dns)
|
||||
{
|
||||
return dns.Split(',').Where(ip => !string.IsNullOrWhiteSpace(ip)).Select(ip => ip.Trim());
|
||||
}
|
||||
|
||||
public static bool TrySplit(string value, out IEnumerable<string> result, ushort maxCount = 0)
|
||||
{
|
||||
result = Split(value).ToArray();
|
||||
|
||||
return maxCount == 0 || result.Count() <= maxCount
|
||||
&&
|
||||
result.All(ip => IPAddress.TryParse(ip, out _));
|
||||
}
|
||||
|
||||
public static string Join(IEnumerable<string> dns)
|
||||
{
|
||||
return string.Join(",", dns);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Netch/Utils/HttpProxyHandler/HttpWebServer.cs
Normal file
99
Netch/Utils/HttpProxyHandler/HttpWebServer.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
public class HttpWebServer
|
||||
{
|
||||
private HttpListener _listener;
|
||||
private Func<HttpListenerRequest, string> _responderMethod;
|
||||
|
||||
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
|
||||
{
|
||||
try
|
||||
{
|
||||
_listener = new HttpListener();
|
||||
|
||||
if (!HttpListener.IsSupported)
|
||||
throw new NotSupportedException(
|
||||
"Needs Windows XP SP2, Server 2003 or later.");
|
||||
|
||||
// URI prefixes are required, for example
|
||||
// "http://localhost:8080/index/".
|
||||
if (prefixes == null || prefixes.Length == 0)
|
||||
throw new ArgumentException("prefixes");
|
||||
|
||||
// A responder method is required
|
||||
if (method == null)
|
||||
throw new ArgumentException("method");
|
||||
|
||||
foreach (string s in prefixes)
|
||||
_listener.Prefixes.Add(s);
|
||||
|
||||
_responderMethod = method;
|
||||
_listener.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error("HttpWebServer():" + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
|
||||
: this(prefixes, method)
|
||||
{
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem((o) =>
|
||||
{
|
||||
Logging.Info("Webserver running...");
|
||||
try
|
||||
{
|
||||
while (_listener.IsListening)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem((c) =>
|
||||
{
|
||||
var ctx = c as HttpListenerContext;
|
||||
try
|
||||
{
|
||||
string rstr = _responderMethod(ctx.Request);
|
||||
byte[] buf = Encoding.UTF8.GetBytes(rstr);
|
||||
ctx.Response.StatusCode = 200;
|
||||
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
|
||||
ctx.Response.ContentLength64 = buf.Length;
|
||||
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
} // suppress any exceptions
|
||||
finally
|
||||
{
|
||||
// always close the stream
|
||||
ctx.Response.OutputStream.Close();
|
||||
}
|
||||
}, _listener.GetContext());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Logging.Error(ex.Message, ex);
|
||||
Logging.Error(ex.Message);
|
||||
} // suppress any exceptions
|
||||
});
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_listener != null)
|
||||
{
|
||||
_listener.Stop();
|
||||
_listener.Close();
|
||||
_listener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
Netch/Utils/HttpProxyHandler/PACServerHandle.cs
Normal file
125
Netch/Utils/HttpProxyHandler/PACServerHandle.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using WindowsProxy;
|
||||
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供PAC功能支持
|
||||
/// </summary>
|
||||
class PACServerHandle
|
||||
{
|
||||
private static Hashtable httpWebServer = new Hashtable();
|
||||
private static Hashtable pacList = new Hashtable();
|
||||
|
||||
public static void InitPACServer(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!pacList.ContainsKey(address))
|
||||
{
|
||||
pacList.Add(address, GetPacList(address));
|
||||
}
|
||||
|
||||
string prefixes = string.Format("http://{0}:{1}/pac/", address, Global.Settings.Pac_Port);
|
||||
|
||||
HttpWebServer ws = new HttpWebServer(SendResponse, prefixes);
|
||||
ws.Run();
|
||||
|
||||
if (!httpWebServer.ContainsKey(address) && ws != null)
|
||||
{
|
||||
httpWebServer.Add(address, ws);
|
||||
}
|
||||
Global.Settings.Pac_Url = GetPacUrl();
|
||||
|
||||
using var service = new ProxyService
|
||||
{
|
||||
AutoConfigUrl = Global.Settings.Pac_Url
|
||||
};
|
||||
service.Pac();
|
||||
|
||||
Logging.Info(service.Set(service.Query()) + "");
|
||||
Logging.Info($"Webserver InitServer OK: {Global.Settings.Pac_Url}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error("Webserver InitServer " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static string SendResponse(HttpListenerRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] arrAddress = request.UserHostAddress.Split(':');
|
||||
string address = "127.0.0.1";
|
||||
if (arrAddress.Length > 0)
|
||||
{
|
||||
address = arrAddress[0];
|
||||
}
|
||||
return pacList[address].ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error("Webserver SendResponse " + ex.Message);
|
||||
return ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (httpWebServer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var key in httpWebServer.Keys)
|
||||
{
|
||||
Logging.Info("Webserver Stop " + key.ToString());
|
||||
((HttpWebServer)httpWebServer[key]).Stop();
|
||||
}
|
||||
httpWebServer.Clear();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error("Webserver Stop " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPacList(string address)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> lstProxy = new List<string>();
|
||||
lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort));
|
||||
|
||||
var proxy = string.Join("", lstProxy.ToArray());
|
||||
string strPacfile = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
|
||||
|
||||
var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
|
||||
return pac;
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return "No pac content";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取PAC地址
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetPacUrl()
|
||||
{
|
||||
string pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port,
|
||||
DateTime.Now.ToString("yyyyMMddHHmmssfff"));
|
||||
|
||||
return pacUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Netch/Utils/HttpProxyHandler/PACUtil.cs
Normal file
56
Netch/Utils/HttpProxyHandler/PACUtil.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Netch.Forms;
|
||||
using Netch.Properties;
|
||||
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供PAC功能支持
|
||||
/// </summary>
|
||||
class PACUtil
|
||||
{
|
||||
private static readonly IEnumerable<char> IgnoredLineBegins = new[] {'!', '['};
|
||||
|
||||
public static List<string> ParseResult(string response)
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(response);
|
||||
string content = Encoding.ASCII.GetString(bytes);
|
||||
List<string> valid_lines = new List<string>();
|
||||
using (var sr = new StringReader(content))
|
||||
{
|
||||
foreach (var line in sr.NonWhiteSpaceLines())
|
||||
{
|
||||
if (line.BeginWithAny(IgnoredLineBegins))
|
||||
continue;
|
||||
valid_lines.Add(line);
|
||||
}
|
||||
}
|
||||
return valid_lines;
|
||||
}
|
||||
|
||||
public static string UnGzip(byte[] buf)
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int n;
|
||||
using (MemoryStream sb = new MemoryStream())
|
||||
{
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(buf),
|
||||
CompressionMode.Decompress,
|
||||
false))
|
||||
{
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
sb.Write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
return System.Text.Encoding.UTF8.GetString(sb.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ using System.Linq;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Socks5;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -66,17 +68,19 @@ namespace Netch.Utils
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (text.First() != '#')
|
||||
return;
|
||||
try
|
||||
{
|
||||
var splited = text.Substring(text.IndexOf('#') + 1).Split(',').Select(s => s.Trim()).ToArray();
|
||||
var splited = text.Substring(1).Split(',').Select(s => s.Trim()).ToArray();
|
||||
|
||||
mode.Remark = splited[0];
|
||||
|
||||
var result = int.TryParse(splited.ElementAtOrDefault(1), out var type);
|
||||
mode.Type = result ? type : 0;
|
||||
var typeResult = int.TryParse(splited.ElementAtOrDefault(1), out var type);
|
||||
mode.Type = typeResult ? type : 0;
|
||||
|
||||
var result1 = int.TryParse(splited.ElementAtOrDefault(2), out var bypassChina);
|
||||
mode.BypassChina = result1 && bypassChina == 1;
|
||||
var bypassChinaResult = int.TryParse(splited.ElementAtOrDefault(2), out var bypassChina);
|
||||
mode.BypassChina = mode.ClientRouting() && bypassChinaResult && bypassChina == 1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -135,6 +139,21 @@ namespace Netch.Utils
|
||||
Global.MainForm.InitMode();
|
||||
}
|
||||
|
||||
|
||||
public static bool SkipServerController(Server server, Mode mode)
|
||||
{
|
||||
return mode.Type switch
|
||||
{
|
||||
0 => server switch
|
||||
{
|
||||
Socks5 => true,
|
||||
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS => true,
|
||||
_ => false
|
||||
},
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName, out PortType portType)
|
||||
{
|
||||
IModeController modeController;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Netch.Servers.Shadowsocks;
|
||||
using Netch.Servers.Shadowsocks.Models;
|
||||
using Netch.Servers.VMess;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Server = Netch.Models.Server;
|
||||
@@ -233,7 +234,8 @@ namespace Netch.Utils
|
||||
|
||||
public static string GetNetchLink(Server s)
|
||||
{
|
||||
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(s));
|
||||
var server = (Server) s.Clone();
|
||||
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(server, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Netch/Utils/StringEx.cs
Normal file
46
Netch/Utils/StringEx.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
static class StringEx
|
||||
{
|
||||
public static bool IsNullOrEmpty(this string value)
|
||||
{
|
||||
return string.IsNullOrEmpty(value);
|
||||
}
|
||||
|
||||
public static bool IsNullOrWhiteSpace(this string value)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(value);
|
||||
}
|
||||
|
||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
return chars.Contains(s[0]);
|
||||
}
|
||||
|
||||
public static bool IsWhiteSpace(this string value)
|
||||
{
|
||||
foreach (var c in value)
|
||||
{
|
||||
if (char.IsWhiteSpace(c)) continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
||||
{
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.IsWhiteSpace()) continue;
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Netch/Utils/Subscription.cs
Normal file
57
Netch/Utils/Subscription.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Subscription
|
||||
{
|
||||
private static readonly object ServerLock = new object();
|
||||
|
||||
public static async Task UpdateServersAsync(string proxyServer = default)
|
||||
{
|
||||
await Task.WhenAll(
|
||||
Global.Settings.SubscribeLink.Select(item =>
|
||||
Task.Run(() => UpdateServer(item, proxyServer))
|
||||
).ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
public static void UpdateServer(SubscribeLink item, string proxyServer)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = WebUtil.CreateRequest(item.Link);
|
||||
|
||||
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;
|
||||
if (!string.IsNullOrEmpty(proxyServer)) request.Proxy = new WebProxy(proxyServer);
|
||||
|
||||
List<Server> servers;
|
||||
|
||||
var result = WebUtil.DownloadString(request, out var rep);
|
||||
if (rep.StatusCode == HttpStatusCode.OK)
|
||||
servers = ShareLink.ParseText(result);
|
||||
else
|
||||
throw new Exception($"{item.Remark} Response Status Code: {rep.StatusCode}");
|
||||
|
||||
foreach (var server in servers) server.Group = item.Remark;
|
||||
|
||||
lock (ServerLock)
|
||||
{
|
||||
Global.Settings.Server.RemoveAll(server => server.Group.Equals(item.Remark));
|
||||
Global.Settings.Server.AddRange(servers);
|
||||
}
|
||||
|
||||
Global.MainForm.NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, servers.Count));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.MainForm.NotifyTip($"{i18N.TranslateFormat("Update servers error from {0}", item.Remark)}\n{e.Message}", info: false);
|
||||
Logging.Error(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
@@ -7,10 +7,12 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using MaxMind.GeoIP2;
|
||||
using TaskScheduler;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -37,12 +39,12 @@ namespace Netch.Utils
|
||||
public static async Task<int> TCPingAsync(IPAddress ip, int port, int timeout = 1000, CancellationToken ct = default)
|
||||
{
|
||||
using var client = new TcpClient(ip.AddressFamily);
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
var task = client.ConnectAsync(ip, port);
|
||||
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
var resTask = await Task.WhenAny(Task.Delay(timeout, ct), task);
|
||||
var resTask = await Task.WhenAny(task, Task.Delay(timeout, ct));
|
||||
|
||||
stopwatch.Stop();
|
||||
if (resTask == task && client.Connected)
|
||||
@@ -54,6 +56,18 @@ namespace Netch.Utils
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public static async Task<int> ICMPing(IPAddress ip, int timeout = 1000)
|
||||
{
|
||||
var reply = new Ping().Send(ip, timeout);
|
||||
|
||||
if (reply?.Status == IPStatus.Success)
|
||||
{
|
||||
return Convert.ToInt32(reply.RoundtripTime);
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public static string GetCityCode(string Hostname)
|
||||
{
|
||||
if (Hostname.Contains(":"))
|
||||
@@ -96,7 +110,7 @@ namespace Netch.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
var sha256 = SHA256.Create();
|
||||
var fileStream = File.OpenRead(filePath);
|
||||
return sha256.ComputeHash(fileStream).Aggregate(string.Empty, (current, b) => current + b.ToString("x2"));
|
||||
}
|
||||
@@ -237,5 +251,62 @@ namespace Netch.Utils
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterNetchStartupItem()
|
||||
{
|
||||
var scheduler = new TaskSchedulerClass();
|
||||
scheduler.Connect();
|
||||
var folder = scheduler.GetFolder("\\");
|
||||
|
||||
var taskIsExists = false;
|
||||
try
|
||||
{
|
||||
folder.GetTask("Netch Startup");
|
||||
taskIsExists = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (Global.Settings.RunAtStartup)
|
||||
{
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
|
||||
var task = scheduler.NewTask(0);
|
||||
task.RegistrationInfo.Author = "Netch";
|
||||
task.RegistrationInfo.Description = "Netch run at startup.";
|
||||
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
|
||||
|
||||
task.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRIGGER_LOGON);
|
||||
var action = (IExecAction) task.Actions.Create(_TASK_ACTION_TYPE.TASK_ACTION_EXEC);
|
||||
action.Path = Application.ExecutablePath;
|
||||
|
||||
|
||||
task.Settings.ExecutionTimeLimit = "PT0S";
|
||||
task.Settings.DisallowStartIfOnBatteries = false;
|
||||
task.Settings.RunOnlyIfIdle = false;
|
||||
|
||||
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null,
|
||||
_TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ChangeControlForeColor(Component component, Color color)
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case TextBox _:
|
||||
case ComboBox _:
|
||||
if (((Control) component).ForeColor != color) ((Control) component).ForeColor = color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,13 @@ namespace Netch.Utils
|
||||
{
|
||||
public static class WebUtil
|
||||
{
|
||||
static WebUtil()
|
||||
{
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
|
||||
}
|
||||
|
||||
public const string DefaultUserAgent =
|
||||
@"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36";
|
||||
@"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55";
|
||||
|
||||
private static int DefaultGetTimeout => Global.Settings.RequestTimeout;
|
||||
|
||||
@@ -47,6 +52,22 @@ namespace Netch.Utils
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载并编码为字符串
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <param name="rep"></param>
|
||||
/// <param name="encoding">编码,默认UTF-8</param>
|
||||
/// <returns></returns>
|
||||
public static string DownloadString(HttpWebRequest req, out HttpWebResponse rep, string encoding = "UTF-8")
|
||||
{
|
||||
rep = (HttpWebResponse) req.GetResponse();
|
||||
using var responseStream = rep.GetResponseStream();
|
||||
using var streamReader = new StreamReader(responseStream, Encoding.GetEncoding(encoding));
|
||||
|
||||
return streamReader.ReadToEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载并编码为字符串
|
||||
/// </summary>
|
||||
@@ -78,4 +99,4 @@ namespace Netch.Utils
|
||||
fileStream.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Platforms>x86;x64</Platforms>
|
||||
<ProjectGuid>{A8715AF4-ACC6-43F9-9381-4294C5360623}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NetchLib</RootNamespace>
|
||||
<AssemblyName>NetchLib</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<NoWarn />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn />
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn />
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn />
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SearchComboBox.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Platforms>x64</Platforms>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -75,7 +75,7 @@ namespace System.Windows.Forms
|
||||
|
||||
private bool IsOriginalItems => Items.Count == AutoFillTag.Length;
|
||||
|
||||
private void ResetCompletionList()
|
||||
public void ResetCompletionList()
|
||||
{
|
||||
Keyword = null;
|
||||
try
|
||||
|
||||
@@ -41,9 +41,7 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
|
||||
|
||||
- [RabbitHosts](https://rabbithosts.com/cart.php)
|
||||
- [ManSora](https://www.mansora.co/cart.php)
|
||||
- [ExCloud](https://excloud.net/cart.php)
|
||||
- [NyanCat](https://nyancat.info/register)
|
||||
- [YoYu](https://home.yoyu.ltd/cart.php)
|
||||
|
||||
## Donate
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
@@ -65,8 +63,11 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
|
||||
- [v2ray-core](https://github.com/v2ray/v2ray-core)
|
||||
- [trojan](https://github.com/trojan-gfw/trojan)
|
||||
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
|
||||
- [GFWList](https://github.com/gfwlist/gfwlist)
|
||||
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
|
||||
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
|
||||
- [Privoxy](https://www.privoxy.org/)
|
||||
- [NatTypeTester](https://github.com/HMBSbige/NatTypeTester)
|
||||
- [NetFilter SDK](https://netfiltersdk.com/)
|
||||
|
||||
[](https://starchart.cc/NetchX/Netch)
|
||||
|
||||
2
binaries
2
binaries
Submodule binaries updated: f081890f60...859ff7b19c
@@ -44,9 +44,7 @@ Netch 是一款 Windows 平台的开源游戏加速工具,Netch 可以实现
|
||||
|
||||
- [RabbitHosts](https://rabbithosts.com/cart.php)
|
||||
- [ManSora](https://www.mansora.co/cart.php)
|
||||
- [ExCloud](https://excloud.net/cart.php)
|
||||
- [NyanCat](https://nyancat.info/register)
|
||||
- [YoYu](https://home.yoyu.ltd/cart.php)
|
||||
|
||||
## 捐赠
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
@@ -74,6 +72,7 @@ Netch 支持多种语言,在启动时会根据系统语言选择自身语言
|
||||
- [v2ray-core](https://github.com/v2ray/v2ray-core)
|
||||
- [trojan](https://github.com/trojan-gfw/trojan)
|
||||
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
|
||||
- [GFWList](https://github.com/gfwlist/gfwlist)
|
||||
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
|
||||
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
|
||||
- [Privoxy](https://www.privoxy.org/)
|
||||
|
||||
2
modes
2
modes
Submodule modes updated: 3ac9f3c380...e3ae0d5406
Submodule translations updated: 45e50093e3...39183c32c0
Reference in New Issue
Block a user