Compare commits

...

87 Commits
1.6.9 ... 1.7.4

Author SHA1 Message Date
ChsBuffer
a853b9831f Bump version to 1.7.4 2021-02-13 14:42:41 +08:00
ChsBuffer
3d37b042f6 Feat: Check if the bin folder exists 2021-02-13 14:38:23 +08:00
ChsBuffer
1f9607ba1e Remove localization folders 2021-02-13 14:24:51 +08:00
ChsBuffer
8443772b75 Add RemoveNetchFirewallRules MenuItem 2021-02-13 14:13:49 +08:00
ChsBuffer
aaad1697b3 Replace NetFwTypeLib COMReference with WindowsFirewallHelper 2021-02-13 14:11:58 +08:00
ChsBuffer
35688003d5 Replace TaskScheduler COMReference with PackageReference 2021-02-13 13:20:11 +08:00
ChsBuffer
19afbf1993 Update stun.txt 2021-02-13 12:45:53 +08:00
ChsBuffer
3cd0b59bf6 Upgrade packages 2021-02-13 12:40:35 +08:00
ChsBuffer
b26aecf7e8 fix ICMPing async warning 2021-02-13 12:39:21 +08:00
ChsBuffer
18f71d3862 Update PostBuild.bat 2021-02-13 12:38:36 +08:00
ChsBuffer
0bd0d06867 Replace v2ray-core with Xray-core 2021-02-13 08:40:47 +08:00
ChsBuffer
96001500f0 Guard.InitInstance() to virtual method 2021-02-12 07:56:42 +08:00
ChsBuffer
11ab1b89af Refactor IServerController 2021-02-12 00:34:17 +08:00
AmazingDM
811e2828fb update submodule 2021-02-09 17:52:29 +08:00
AmazingDM
68a2e4b705 Update UpdateChecker.cs 2021-02-08 11:41:45 +08:00
ChsBuffer
8e83359e39 Bump version to 1.7.3 2021-01-26 21:57:24 +08:00
ChsBuffer
d2b6d182ff Remove Delay Test "Test done" Notification 2021-01-26 21:51:47 +08:00
ChsBuffer
019044c275 Refactor:
Move NatTest to MainForm
  Move call NetTraffic() NatTest() to ControlButton_Click()
2021-01-26 21:50:33 +08:00
ChsBuffer
df48eb3067 Disable Update Servers with proxy when started 2021-01-26 21:43:33 +08:00
ChsBuffer
6bfcae453f Fix #498 , again 2021-01-26 21:36:23 +08:00
ChsBuffer
7d55af2101 Fix speed test caused lost status port info 2021-01-26 00:59:46 +08:00
ChsBuffer
9172ede7c2 Refactor DrawItem 2021-01-18 05:51:38 +08:00
ChsBuffer
fb8aa548ac Cut: Exclude Server.Delay property from serialization. 2021-01-18 04:11:10 +08:00
ChsBuffer
46643a3f5e Fix: Detection Tick be enabled by MainForm.State even disabled by value 0 2021-01-18 04:06:28 +08:00
ChsBuffer
99752d7a44 Refactor Check settings change
Refactor Check Detection Tick value
Fix sometimes Detection Tick not update
2021-01-18 01:01:07 +08:00
ChsBuffer
004b84ceda Fix #498 2021-01-16 22:40:05 +08:00
ChsBuffer
d15206b803 Bump version to 1.7.2 2021-01-15 19:57:28 +08:00
ChsBuffer
754753300d Refactor Test All Server Delay Tick 2021-01-15 19:53:44 +08:00
ChsBuffer
aa021aaf79 Fix Build 2021-01-15 19:43:09 +08:00
ChsBuffer
c50ca563b2 Improve Force Exit 2021-01-15 19:42:49 +08:00
ChsBuffer
a1fdf7ead2 Update SettingForm 2021-01-15 18:09:36 +08:00
ChsBuffer
c9da7197ba Refactor: Merge MainForm 2021-01-15 16:24:59 +08:00
ChsBuffer
5ff26e97b4 trim 2021-01-14 20:13:15 +08:00
ChsBuffer
06049cb06f Refactor Servers Test Delay Interval 2021-01-14 19:52:23 +08:00
ChsBuffer
8cf765de92 Feat: Update Download Progress 2021-01-14 16:28:14 +08:00
ChsBuffer
2b53a7ca9e Refactor UpdateChecker.cs 2021-01-14 15:54:17 +08:00
ChsBuffer
c7c0a2a698 Update README 2021-01-13 21:16:53 +08:00
ChsBuffer
1d072214ee Refactor Check Port 2021-01-13 20:22:15 +08:00
AmazingDM
135ff642bd Update NF driver to 1.6.0.2 2021-01-13 09:53:52 +08:00
Connection Refused
4c274a1888 Update zh-CN 2021-01-13 02:23:11 +08:00
ChsBuffer
59cfc071cc [Break] Rename UpdateSubscribeatWhenOpened to UpdateServersWhenOpened 2021-01-12 19:13:14 +08:00
ChsBuffer
8cf32e5d37 Feat: MainForm.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem,
"Update server at startup" uses proxy based on the last update servers operation
2021-01-12 19:02:27 +08:00
ChsBuffer
7a1e5b58b9 SubscribeForm: Refactor 2021-01-12 18:28:38 +08:00
ChsBuffer
651fbb6ff9 SubscribeForm: Fix Enable Checked Event, Organize code 2021-01-12 17:46:52 +08:00
ChsBuffer
45bf31e9f3 Fix SubscribeForm Edit 2021-01-12 17:02:57 +08:00
AmazingDM
f7c9ab4028 Update NTT to 3.4 2021-01-11 17:10:19 +08:00
AmazingDM
717dc55055 Delete subscribeForm alert 2021-01-11 11:54:25 +08:00
ChsBuffer
a0c4dd3192 Replace NetchCore with RouteHelper 2021-01-10 20:58:49 +08:00
AmazingDM
325ad430fe Bump version to 1.7.1 2021-01-09 02:33:00 +00:00
ChsBuffer
4b374d3898 Disable Update PAC when started 2021-01-07 11:01:23 +08:00
ChsBuffer
b6afeab187 trim 2021-01-07 10:54:50 +08:00
ChsBuffer
6e499c3948 Update Option items Notification 2021-01-07 10:52:58 +08:00
ChsBuffer
5bfcbab543 Comment ExitToolStripMenuIten_Click Handler 2021-01-05 18:10:10 +08:00
ChsBuffer
fe69c5a67b Refactor show Bandwidth 2021-01-05 17:55:08 +08:00
ChsBuffer
1c974d295b Revert "️"
This reverts commit a544bd1a26.
2021-01-05 17:54:00 +08:00
AmazingDM
a544bd1a26 2021-01-05 17:37:14 +08:00
AmazingDM
3bfe03b99b 更新添加模式窗口汉化,优化代码 2021-01-05 17:21:36 +08:00
AmazingDM
1fa18ce787 Merge branch 'master' of https://github.com/NetchX/Netch 2021-01-05 17:12:50 +08:00
AmazingDM
f7ad2baa52 Optimized code 2021-01-05 17:11:11 +08:00
AmazingDM
447a25457b Update Advanced_Usage.zh-CN.md 2021-01-05 16:44:46 +08:00
AmazingDM
3a8351e6e4 Update README.md 2021-01-05 16:39:54 +08:00
AmazingDM
eb30300b24 Update README.zh-CN.md 2021-01-05 16:39:50 +08:00
AmazingDM
0b8373a21e Update README.md 2021-01-05 16:34:37 +08:00
AmazingDM
8a551b715e 订阅链接启用状态默认为true 2021-01-05 13:01:16 +08:00
AmazingDM
34814fe7f5 订阅窗口可右键删除订阅节点
新增订阅链接勾选项(订阅启用状态)
更新订阅窗口汉化
2021-01-05 11:55:04 +08:00
AmazingDM
528abe3fdd Socks5无验证时不显示流量统计
更新PAC
2021-01-04 18:45:01 +08:00
AmazingDM
a10410dafd Update ck-client to v2.5.2 https://github.com/cbeuw/Cloak/releases/tag/v2.5.2 2021-01-04 15:22:46 +08:00
AmazingDM
2ca98a94d5 rename UninstallTap method 2021-01-04 15:09:01 +08:00
AmazingDM
ac2e5e943e Update mode 2021-01-04 14:05:15 +08:00
AmazingDM
0957514e05 Bump version to 1.7.0 2021-01-04 14:01:20 +08:00
AmazingDM
35b9f168ff 添加测速方式(TCPing&ICMPing)切换设置选项 2021-01-04 13:59:19 +08:00
AmazingDM
ce15e9468e 不代理TCP流量设置
调整设置界面UI
2021-01-04 13:23:58 +08:00
AmazingDM
4c8508a838 Merge remote-tracking branch 'chsbuffer/fixJob' 2021-01-04 12:45:19 +08:00
ChsBuffer
f931adb005 Fix TrojanController ignores sni (host) value
closes #478, #487
2020-12-31 15:04:53 +08:00
Connection Refused
d4f829d4bd Merge pull request #486 from SekiBetu/dev
set mux to false by default
2020-12-30 09:26:44 +08:00
SekiBetu
51d4ba0fdb set mux to false by default 2020-12-30 06:37:02 +08:00
AmazingDM
ca0870889a 更新NTT,优化部分代码 2020-12-28 15:21:43 +08:00
ChsBuffer
ac3e39e9cd Update AioDNS 2020-12-25 22:44:44 +08:00
ChsBuffer
84765ab96d Delay Add Job 2020-12-25 17:12:03 +08:00
AmazingDM
a18851af15 Update binaries 2020-12-25 13:48:40 +08:00
AmazingDM
42366abcca Update README.md Quote 2020-12-25 13:43:33 +08:00
AmazingDM
cec8358922 PAC 2020-12-25 11:28:38 +08:00
AmazingDM
db8e964351 Update translations 2020-12-25 09:43:48 +08:00
AmazingDM
ad3053298a PAC替换ACL
sysproxy.dll 替换为 nuget WindowsProxy
2020-12-24 22:57:52 +08:00
ChsBuffer
669ca4902f Fix: set encoding only when RedireStd enabled 2020-12-24 16:14:41 +08:00
ChsBuffer
272bf61b0f Remove RedirecStandInput (Fix SS plugin start error) 2020-12-24 15:59:51 +08:00
ChsBuffer
0051e7bb50 Feat ICMPing 2020-12-24 13:32:06 +08:00
70 changed files with 3188 additions and 2905 deletions

View File

@@ -1,7 +1,7 @@
root = true
# http://editorconfig.org/
# top-most EditorConfig file
root = true
# all files
[*]
@@ -32,6 +32,7 @@ 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_keep_blank_lines_in_declarations = 1
resharper_csharp_max_line_length = 368
resharper_csharp_wrap_lines = false
resharper_place_expr_accessor_on_single_line = true

View File

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

View File

@@ -14,12 +14,12 @@ namespace Netch.Controllers
{
public abstract class Guard
{
public abstract string Name { get; protected set; }
public virtual string Name { get; }
/// <summary>
/// 主程序名
/// </summary>
public abstract string MainFile { get; protected set; }
public virtual string MainFile { get; protected set; }
protected State State { get; set; } = State.Waiting;
@@ -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>
/// 停止进程
@@ -83,7 +83,7 @@ namespace Netch.Controllers
/// 仅初始化 <see cref="Instance"/>,不设定事件处理方法
/// </summary>
/// <param name="argument"></param>
protected void InitInstance(string argument)
protected virtual void InitInstance(string argument)
{
Instance = new Process
{
@@ -93,16 +93,16 @@ 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
}
};
}
/// <summary>
/// 默认行为启动主程序
/// </summary>
@@ -192,15 +192,13 @@ namespace Netch.Controllers
if (e.Data == null)
return;
var info = Encoding.GetEncoding(InstanceOutputEncoding).GetBytes(e.Data);
var str = Encoding.UTF8.GetString(info);
Write(str);
Write(e.Data);
// 检查启动
if (State == State.Starting)
{
if (StartedKeywords.Any(s => str.Contains(s)))
if (StartedKeywords.Any(s => e.Data.Contains(s)))
State = State.Started;
else if (StoppedKeywords.Any(s => str.Contains(s)))
else if (StoppedKeywords.Any(s => e.Data.Contains(s)))
State = State.Stopped;
}
}

View File

@@ -2,10 +2,14 @@ using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsProxy;
using Microsoft.Win32;
using Netch.Forms;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Servers.Trojan;
using Netch.Utils;
using Netch.Utils.HttpProxyHandler;
namespace Netch.Controllers
{
@@ -13,7 +17,7 @@ namespace Netch.Controllers
{
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
public PrivoxyController pPrivoxyController = new PrivoxyController();
public PrivoxyController pPrivoxyController = new();
private string prevBypass, prevHTTP, prevPAC;
private bool prevEnabled;
@@ -32,11 +36,25 @@ namespace Netch.Controllers
try
{
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 (MainController.Server is Socks5 or Trojan && 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)
{
@@ -49,6 +67,48 @@ namespace Netch.Controllers
return true;
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
var tasks = new[]
{
Task.Run(pPrivoxyController.Stop),
Task.Run(() =>
{
using var service = new ProxyService();
try
{
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);
}
})
};
Task.WaitAll(tasks);
}
private void RecordPrevious()
{
try
@@ -77,29 +137,5 @@ namespace Netch.Controllers
prevPAC = prevHTTP = prevBypass = "";
}
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
var tasks = new[]
{
Task.Factory.StartNew(pPrivoxyController.Stop),
Task.Factory.StartNew(() =>
{
if (prevEnabled)
{
if (prevHTTP != "")
NativeMethods.SetGlobal(prevHTTP, prevBypass);
if (prevPAC != "")
NativeMethods.SetURL(prevPAC);
}
else
NativeMethods.SetDIRECT();
})
};
Task.WaitAll(tasks);
}
}
}

View File

@@ -10,6 +10,6 @@
/// <summary>
/// 停止
/// </summary>
public abstract void Stop();
public void Stop();
}
}

View File

@@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Netch.Forms;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
@@ -12,6 +14,17 @@ namespace Netch.Controllers
{
public static class MainController
{
public static Mode Mode;
/// TCP or Both Server
public static Server Server;
private static Server _udpServer;
public static readonly NTTController NTTController = new();
private static IServerController _serverController;
private static IServerController _udpServerController;
public static IServerController ServerController
{
get => _serverController;
@@ -24,24 +37,14 @@ namespace Netch.Controllers
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>
/// 启动
/// </summary>
@@ -52,11 +55,10 @@ namespace Netch.Controllers
{
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
Server = server;
Mode = mode;
if (server is Socks5 && mode.Type == 4)
{
return false;
}
// 刷新DNS缓存
NativeMethods.FlushDNSResolverCache();
@@ -85,20 +87,13 @@ namespace Netch.Controllers
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 (mode.TestNatRequired())
NatTest();
return true;
}
@@ -111,7 +106,6 @@ namespace Netch.Controllers
MessageBoxX.Show(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"), owner: Global.MainForm);
break;
case StartFailedException _:
case PortInUseException _:
break;
default:
Logging.Error($"主控制器未处理异常: {e}");
@@ -136,31 +130,30 @@ namespace Netch.Controllers
controller = ServerHelper.GetUtilByTypeName(server.Type).GetController();
if (controller is Guard instanceController)
{
Utils.Utils.KillProcessByName(instanceController.MainFile);
}
PortCheckAndShowMessageBox(controller.Socks5LocalPort(), "Socks5");
if (!PortCheckAndShowMessageBox(controller.Socks5LocalPort(), "Socks5"))
return false;
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", controller.Name));
if (controller.Start(in server, mode))
{
if (controller is Guard guard)
{
if (guard.Instance != null)
{
Global.Job.AddProcess(guard.Instance);
}
}
Task.Run(() =>
{
Thread.Sleep(1000);
Global.Job.AddProcess(guard.Instance);
});
if (server is Socks5 socks5)
{
if (socks5.Auth())
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
StatusPortInfoText.Socks5Port = controller.Socks5LocalPort();
}
else
{
UsingPorts.Add(StatusPortInfoText.Socks5Port = controller.Socks5LocalPort());
StatusPortInfoText.Socks5Port = controller.Socks5LocalPort();
}
return true;
@@ -174,26 +167,18 @@ namespace Netch.Controllers
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 (!PortCheckAndShowMessageBox((ushort) port, portName, portType))
return false;
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
if (await Task.Run(() => ModeController.Start(mode)))
{
if (ModeController is Guard guard)
{
if (guard.Instance != null)
{
Global.Job.AddProcess(guard.Instance);
}
}
return true;
}
@@ -206,7 +191,6 @@ namespace Netch.Controllers
/// </summary>
public static async Task Stop()
{
UsingPorts.Clear();
StatusPortInfoText.Reset();
_ = Task.Run(() => NTTController.Stop());
@@ -214,53 +198,34 @@ namespace Netch.Controllers
var tasks = new[]
{
Task.Run(() => ServerController?.Stop()),
Task.Run(() => ModeController?.Stop()),
Task.Run(() => ModeController?.Stop())
};
await Task.WhenAll(tasks);
ModeController = null;
ServerController = null;
}
/// <summary>
/// 检查端口是否被占用,
/// 检查端口是否被占用,
/// 被占用则弹窗提示, 确认后抛出异常
/// </summary>
/// <param name="port">检查的端口</param>
/// <param name="portName">端口用途名称</param>
/// <param name="portType"></param>
/// <exception cref="PortInUseException"></exception>
public static void PortCheckAndShowMessageBox(ushort port, string portName, PortType portType = PortType.Both)
public static bool PortCheckAndShowMessageBox(ushort port, string portName, PortType portType = PortType.Both)
{
if (PortInUse(port, portType))
try
{
CheckPort(port, portType);
return true;
}
catch (PortInUseException)
{
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", $"{portName} ({port})"));
throw new PortInUseException();
return false;
}
}
/// <summary>
/// 测试 NAT
/// </summary>
public static void NatTest()
{
NttTested = false;
Task.Run(() =>
catch (PortReservedException)
{
Global.MainForm.NatTypeStatusText(i18N.Translate("Starting NatTester"));
// Thread.Sleep(1000);
var (result, localEnd, publicEnd) = NTTController.Start();
if (!string.IsNullOrEmpty(publicEnd))
{
var country = Utils.Utils.GetCityCode(publicEnd);
Global.MainForm.NatTypeStatusText(result, country);
}
else
Global.MainForm.NatTypeStatusText(result ?? "Error");
NttTested = true;
});
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is reserved by system.", $"{portName} ({port})"));
return false;
}
}
}

View File

@@ -5,6 +5,7 @@ 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;
@@ -15,14 +16,12 @@ namespace Netch.Controllers
{
public class NFController : IModeController
{
private static readonly ServiceController NFService = new ServiceController("netfilter2");
private static readonly ServiceController NFService = new("netfilter2");
private static readonly string BinDriver = string.Empty;
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
private static string _sysDns;
public string Name { get; } = "Redirector";
static NFController()
{
string fileName;
@@ -47,6 +46,8 @@ namespace Netch.Controllers
BinDriver = "bin\\" + fileName;
}
public string Name { get; } = "Redirector";
public bool Start(in Mode mode)
{
if (!CheckDriver())
@@ -55,8 +56,11 @@ namespace Netch.Controllers
#region aio_dial
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp) MessageBoxX.Show("");
//UDP
if (Global.Settings.ProcessNoProxyForUdp)
{
aio_dial((int) NameList.TYPE_FILTERUDP, "false");
@@ -68,6 +72,18 @@ namespace Netch.Controllers
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");
@@ -90,8 +106,19 @@ namespace Netch.Controllers
return aio_init();
}
public void Stop()
{
Task.Run(() =>
{
if (Global.Settings.ModifySystemDNS)
//恢复系统DNS
DNS.OutboundDNS = _sysDns;
});
aio_free();
}
/// <summary>
///
/// </summary>
/// <param name="rules"></param>
/// <param name="incompatibleRule"></param>
@@ -104,7 +131,6 @@ namespace Netch.Controllers
}
/// <summary>
///
/// </summary>
/// <param name="r"></param>
/// <param name="clear"></param>
@@ -146,9 +172,7 @@ namespace Netch.Controllers
}
if (!File.Exists(SystemDriver))
{
return InstallDriver();
}
var updateFlag = false;
@@ -163,18 +187,14 @@ namespace Netch.Controllers
{
// 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;
@@ -252,18 +272,6 @@ namespace Netch.Controllers
aio_dial((int) NameList.TYPE_ADDNAME, @"NTT\.exe");
}
public void Stop()
{
Task.Run(() =>
{
if (Global.Settings.ModifySystemDNS)
//恢复系统DNS
DNS.OutboundDNS = _sysDns;
});
aio_free();
}
#region NativeMethods
private const int UdpNameListOffset = (int) NameList.TYPE_UDPTYPE - (int) NameList.TYPE_TCPTYPE;
@@ -284,7 +292,7 @@ namespace Netch.Controllers
private static extern ulong aio_getDL();
public enum NameList : int
public enum NameList
{
TYPE_FILTERLOOPBACK,
TYPE_FILTERTCP,
@@ -348,7 +356,6 @@ namespace Netch.Controllers
/// <returns>是否成功卸载</returns>
public static bool UninstallDriver()
{
Global.MainForm.StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
Logging.Info("卸载 NF 驱动");
try
{

View File

@@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Netch.Utils;
@@ -8,7 +7,7 @@ namespace Netch.Controllers
{
public class NTTController : Guard, IController
{
public override string Name { get; protected set; } = "NTT";
public override string Name { get; } = "NTT";
public override string MainFile { get; protected set; } = "NTT.exe";
/// <summary>
@@ -17,10 +16,10 @@ namespace Netch.Controllers
/// <returns></returns>
public (string, string, string) Start()
{
string localEnd=null;
string publicEnd=null;
string result =null;
string bindingTest=null;
string localEnd = null;
string publicEnd = null;
string result = null;
string bindingTest = null;
try
{

View File

@@ -12,7 +12,7 @@ namespace Netch.Controllers
RedirectStd = false;
}
public override string Name { get; protected set; } = "Privoxy";
public override string Name { get; } = "Privoxy";
public override string MainFile { get; protected set; } = "Privoxy.exe";

View File

@@ -15,7 +15,9 @@ namespace Netch.Controllers
{
public class TUNTAPController : Guard, IModeController
{
private readonly List<string> _directIPs = new();
private readonly List<string> _proxyIPs = new();
/// <summary>
/// 服务器 IP 地址
/// </summary>
@@ -24,17 +26,17 @@ namespace Netch.Controllers
/// <summary>
/// 本地 DNS 服务控制器
/// </summary>
public DNSController DNSController = new DNSController();
public DNSController DNSController = new();
public TUNTAPController()
{
StartedKeywords.Add("Running");
StoppedKeywords.AddRange(new[] {"failed", "invalid vconfig file"});
}
public override string Name { get; protected set; } = "tun2socks";
public override string MainFile { get; protected set; } = "tun2socks.exe";
public override string Name { get; } = "tun2socks";
public bool Start(in Mode mode)
{
var server = MainController.Server;
@@ -43,9 +45,7 @@ namespace Netch.Controllers
// 查找出口适配器
if (!Utils.Utils.SearchOutboundAdapter())
{
return false;
}
// 查找并安装 TAP 适配器
if (!SearchTapAdapter())
@@ -79,14 +79,8 @@ namespace Netch.Controllers
}
else
{
try
{
MainController.PortCheckAndShowMessageBox(53, "DNS");
}
catch
{
if (!MainController.PortCheckAndShowMessageBox(53, "DNS"))
return false;
}
if (!DNSController.Start())
{
@@ -119,17 +113,13 @@ 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);
}
private readonly List<string> _directIPs = new List<string>();
private readonly List<string> _proxyIPs = new List<string>();
/// <summary>
/// 设置绕行规则
/// </summary>
@@ -150,7 +140,6 @@ namespace Netch.Controllers
//处理 NAT 类型检测,由于协议的原因,无法仅通过域名确定需要代理的 IP自己记录解析了返回的 IP仅支持默认检测服务器
if (Global.Settings.STUN_Server == "stun.stunprotocol.org")
{
try
{
Logging.Info("代理 → STUN 服务器 IP");
@@ -166,23 +155,18 @@ namespace Netch.Controllers
{
Logging.Info("NAT 类型测试域名解析失败,将不会被添加到代理列表");
}
}
if (Global.Settings.TUNTAP.ProxyDNS)
{
Logging.Info("代理 → 自定义 DNS");
if (Global.Settings.TUNTAP.UseCustomDNS)
{
RouteAction(Action.Create,
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
else
{
RouteAction(Action.Create,
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
RouteType.TUNTAP);
}
}
break;
@@ -222,7 +206,6 @@ namespace Netch.Controllers
}
}
/// <summary>
/// 清除绕行规则
/// </summary>
@@ -235,7 +218,6 @@ namespace Netch.Controllers
return true;
}
public bool TestFakeDNS()
{
try
@@ -303,26 +285,11 @@ namespace Netch.Controllers
return true;
}
private enum RouteType
{
Outbound,
TUNTAP
}
private enum Action
{
Create,
Delete
}
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType,
int metric = 0)
{
foreach (var address in ipNetworks)
{
RouteAction(action, address, routeType, metric);
}
}
private bool RouteAction(Action action, in string ipNetwork, RouteType routeType, int metric = 0)
@@ -383,11 +350,21 @@ namespace Netch.Controllers
}
if (!result)
{
Logging.Warning($"Failed to {action} Route on {routeType} Adapter: {ipNetwork} metric {metric}");
}
return result;
}
private enum RouteType
{
Outbound,
TUNTAP
}
private enum Action
{
Create,
Delete
}
}
}

View File

@@ -1,35 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Netch.Models.GitHubRelease;
using Netch.Utils;
using Newtonsoft.Json;
namespace Netch.Controllers
{
public class UpdateChecker
public static class UpdateChecker
{
public const string Owner = @"NetchX";
public const string Repo = @"Netch";
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2020";
public const string Copyright = @"Copyright © 2019 - 2021";
public const string AssemblyVersion = @"1.6.9";
public const string AssemblyVersion = @"1.7.4";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
public string LatestVersionNumber;
public string LatestVersionUrl;
public Release LatestRelease;
public static string LatestVersionNumber;
public static string LatestVersionUrl;
public static Release LatestRelease;
public event EventHandler NewVersionFound;
public event EventHandler NewVersionFoundFailed;
public event EventHandler NewVersionNotFound;
public static event EventHandler NewVersionFound;
public static event EventHandler NewVersionFoundFailed;
public static event EventHandler NewVersionNotFound;
public async void Check(bool isPreRelease)
public static async void Check(bool isPreRelease)
{
try
{
@@ -46,12 +49,12 @@ namespace Netch.Controllers
if (VersionUtil.CompareVersion(LatestRelease.tag_name, Version) > 0)
{
Logging.Info("发现新版本");
NewVersionFound?.Invoke(this, new EventArgs());
NewVersionFound?.Invoke(null, new EventArgs());
}
else
{
Logging.Info("目前是最新版本");
NewVersionNotFound?.Invoke(this, new EventArgs());
NewVersionNotFound?.Invoke(null, new EventArgs());
}
}
catch (Exception e)
@@ -59,12 +62,67 @@ namespace Netch.Controllers
if (e is WebException)
Logging.Warning($"获取新版本失败: {e.Message}");
else
{
Logging.Warning(e.ToString());
NewVersionFoundFailed?.Invoke(null, new EventArgs());
}
}
public static async Task UpdateNetch(DownloadProgressChangedEventHandler onDownloadProgressChanged)
{
using WebClient client = new();
var latestVersionDownloadUrl = LatestRelease.assets[0].browser_download_url;
var tagPage = await client.DownloadStringTaskAsync(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('.'), LatestVersionNumber);
var fileFullPath = Path.Combine(Global.NetchDir, "data", fileName);
var sha256 = match.Groups["sha256"].Value;
if (File.Exists(fileFullPath))
{
if (Utils.Utils.SHA256CheckSum(fileFullPath) == sha256)
{
RunUpdater();
return;
}
NewVersionFoundFailed?.Invoke(this, new EventArgs());
File.Delete(fileFullPath);
}
try
{
client.DownloadProgressChanged += onDownloadProgressChanged;
await client.DownloadFileTaskAsync(new Uri(latestVersionDownloadUrl), fileFullPath);
client.DownloadProgressChanged -= onDownloadProgressChanged;
}
catch (Exception e)
{
throw new Exception(i18N.Translate("Download Update Failed", ": ") + e.Message);
}
if (Utils.Utils.SHA256CheckSum(fileFullPath) != sha256)
throw new Exception(i18N.Translate("The downloaded file has the wrong hash"));
RunUpdater();
void RunUpdater()
{
// if debugging process stopped, debugger will kill child processes!!!!
// 调试进程结束,调试器将会杀死子进程
// uncomment if(!Debugger.isAttach) block in NetchUpdater Project's main() method and attach to NetchUpdater process to debug
// 在 NetchUpdater 项目的 main() 方法中取消注释 if!Debugger.isAttach并附加到 NetchUpdater 进程进行调试
Process.Start(new ProcessStartInfo
{
FileName = Path.Combine(Global.NetchDir, "NetchUpdater.exe"),
Arguments =
$"{Global.Settings.UDPSocketPort} \"{fileFullPath}\" \"{Global.NetchDir}\""
});
}
}
}
}
}

View File

@@ -1,127 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Models;
using Netch.Utils;
namespace Netch.Forms
{
public partial class Dummy
{
}
partial class MainForm
{
private bool _isFirstCloseWindow = true;
private async void ControlFun()
{
Configuration.Save();
if (State == State.Waiting || State == State.Stopped)
{
// 服务器、模式 需选择
if (!(ServerComboBox.SelectedItem is Server server))
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
if (!(ModeComboBox.SelectedItem is Models.Mode mode))
{
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
return;
}
// 清除模式搜索框文本选择
ModeComboBox.Select(0, 0);
State = State.Starting;
if (await MainController.Start(server, mode))
{
State = State.Started;
_ = Task.Run(() => { Bandwidth.NetTraffic(server, mode); });
// 如果勾选启动后最小化
if (Global.Settings.MinimizeWhenStarted)
{
WindowState = FormWindowState.Minimized;
if (_isFirstCloseWindow)
{
// 显示提示语
NotifyTip(i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."));
_isFirstCloseWindow = false;
}
Hide();
}
if (Global.Settings.StartedTcping)
{
// 自动检测延迟
_ = Task.Run(() =>
{
while (State == State.Started)
{
server.Test();
// 重绘 ServerComboBox
ServerComboBox.Invalidate();
Thread.Sleep(Global.Settings.StartedTcping_Interval * 1000);
}
});
}
}
else
{
State = State.Stopped;
StatusText(i18N.Translate("Start failed"));
}
}
else
{
// 停止
State = State.Stopping;
await MainController.Stop();
State = State.Stopped;
_ = Task.Run(TestServer);
}
}
public void OnBandwidthUpdated(ulong download)
{
if (InvokeRequired)
{
BeginInvoke(new Action<ulong>(OnBandwidthUpdated), download);
return;
}
try
{
UsedBandwidthLabel.Text = $"{i18N.Translate("Used", ": ")}{Bandwidth.Compute(download)}";
//UploadSpeedLabel.Text = $"↑: {Utils.Bandwidth.Compute(upload - LastUploadBandwidth)}/s";
DownloadSpeedLabel.Text = $"↑↓: {Bandwidth.Compute(download - LastDownloadBandwidth)}/s";
//LastUploadBandwidth = upload;
LastDownloadBandwidth = download;
Refresh();
}
catch
{
// ignored
}
}
/// <summary>
/// 上一次上传的流量
/// </summary>
public ulong LastUploadBandwidth;
/// <summary>
/// 上一次下载的流量
/// </summary>
public ulong LastDownloadBandwidth;
}
}

View File

@@ -39,11 +39,13 @@
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ManageSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UpdateServersFromSubscribeLinksToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.OptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.OpenDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.CleanDNSCacheToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UpdateACLToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.updateACLWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UninstallTapDriverToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.HelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -87,17 +89,18 @@
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl();
this.removeNetchFirewallRulesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MenuStrip.SuspendLayout();
this.ConfigurationGroupBox.SuspendLayout();
this.configLayoutPanel.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.EditServerPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.CopyLinkPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.DeleteServerPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize) (this.EditServerPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize) (this.CopyLinkPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize) (this.DeleteServerPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize) (this.SpeedPictureBox)).BeginInit();
this.tableLayoutPanel3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.EditModePictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.DeleteModePictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize) (this.EditModePictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize) (this.DeleteModePictureBox)).BeginInit();
this.StatusStrip.SuspendLayout();
this.NotifyMenu.SuspendLayout();
this.ProfileGroupBox.SuspendLayout();
@@ -109,16 +112,10 @@
//
this.MenuStrip.BackColor = System.Drawing.SystemColors.Control;
this.MenuStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.MenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ServerToolStripMenuItem,
this.ModeToolStripMenuItem,
this.SubscribeToolStripMenuItem,
this.OptionsToolStripMenuItem,
this.HelpToolStripMenuItem,
this.exitToolStripMenuItem,
this.AboutToolStripButton,
this.NewVersionLabel,
this.VersionLabel});
this.MenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.ServerToolStripMenuItem, this.ModeToolStripMenuItem, this.SubscribeToolStripMenuItem, this.OptionsToolStripMenuItem, this.HelpToolStripMenuItem, this.exitToolStripMenuItem, this.AboutToolStripButton, this.NewVersionLabel, this.VersionLabel
});
this.MenuStrip.Location = new System.Drawing.Point(0, 0);
this.MenuStrip.Name = "MenuStrip";
this.MenuStrip.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional;
@@ -127,8 +124,10 @@
//
// ServerToolStripMenuItem
//
this.ServerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ImportServersFromClipboardToolStripMenuItem});
this.ServerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.ImportServersFromClipboardToolStripMenuItem
});
this.ServerToolStripMenuItem.Margin = new System.Windows.Forms.Padding(3, 0, 0, 1);
this.ServerToolStripMenuItem.Name = "ServerToolStripMenuItem";
this.ServerToolStripMenuItem.Size = new System.Drawing.Size(57, 21);
@@ -143,9 +142,10 @@
//
// ModeToolStripMenuItem
//
this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.CreateProcessModeToolStripMenuItem,
this.ReloadModesToolStripMenuItem});
this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.CreateProcessModeToolStripMenuItem, this.ReloadModesToolStripMenuItem
});
this.ModeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.ModeToolStripMenuItem.Name = "ModeToolStripMenuItem";
this.ModeToolStripMenuItem.Size = new System.Drawing.Size(55, 21);
@@ -167,9 +167,10 @@
//
// SubscribeToolStripMenuItem
//
this.SubscribeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ManageSubscribeLinksToolStripMenuItem,
this.UpdateServersFromSubscribeLinksToolStripMenuItem});
this.SubscribeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.ManageSubscribeLinksToolStripMenuItem, this.UpdateServersFromSubscribeLinksToolStripMenuItem, this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem
});
this.SubscribeToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.SubscribeToolStripMenuItem.Name = "SubscribeToolStripMenuItem";
this.SubscribeToolStripMenuItem.Size = new System.Drawing.Size(77, 21);
@@ -178,26 +179,30 @@
// ManageSubscribeLinksToolStripMenuItem
//
this.ManageSubscribeLinksToolStripMenuItem.Name = "ManageSubscribeLinksToolStripMenuItem";
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
this.ManageSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
this.ManageSubscribeLinksToolStripMenuItem.Text = "Manage Subscribe Links";
this.ManageSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.ManageSubscribeLinksToolStripMenuItem_Click);
//
// UpdateServersFromSubscribeLinksToolStripMenuItem
//
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksToolStripMenuItem";
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(294, 22);
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Text = "Update Servers From Subscribe Links";
this.UpdateServersFromSubscribeLinksToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscribeLinksToolStripMenuItem_Click);
//
// UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem
//
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Name = "UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem";
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Size = new System.Drawing.Size(360, 22);
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Text = "Update Servers From Subscribe Links With Proxy";
this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Click += new System.EventHandler(this.UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem_Click);
//
// OptionsToolStripMenuItem
//
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.OpenDirectoryToolStripMenuItem,
this.CleanDNSCacheToolStripMenuItem,
this.UpdateACLToolStripMenuItem,
this.updateACLWithProxyToolStripMenuItem,
this.UninstallServiceToolStripMenuItem,
this.UninstallTapDriverToolStripMenuItem});
this.OptionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.OpenDirectoryToolStripMenuItem, this.CleanDNSCacheToolStripMenuItem, this.UpdateACLToolStripMenuItem, this.updateACLWithProxyToolStripMenuItem, this.updatePACToolStripMenuItem, this.UninstallServiceToolStripMenuItem, this.UninstallTapDriverToolStripMenuItem, this.removeNetchFirewallRulesToolStripMenuItem
});
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.OptionsToolStripMenuItem.Name = "OptionsToolStripMenuItem";
this.OptionsToolStripMenuItem.Size = new System.Drawing.Size(66, 21);
@@ -206,50 +211,58 @@
// OpenDirectoryToolStripMenuItem
//
this.OpenDirectoryToolStripMenuItem.Name = "OpenDirectoryToolStripMenuItem";
this.OpenDirectoryToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.OpenDirectoryToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.OpenDirectoryToolStripMenuItem.Text = "Open Directory";
this.OpenDirectoryToolStripMenuItem.Click += new System.EventHandler(this.OpenDirectoryToolStripMenuItem_Click);
//
// CleanDNSCacheToolStripMenuItem
//
this.CleanDNSCacheToolStripMenuItem.Name = "CleanDNSCacheToolStripMenuItem";
this.CleanDNSCacheToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.CleanDNSCacheToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.CleanDNSCacheToolStripMenuItem.Text = "Clean DNS Cache";
this.CleanDNSCacheToolStripMenuItem.Click += new System.EventHandler(this.CleanDNSCacheToolStripMenuItem_Click);
//
// UpdateACLToolStripMenuItem
//
this.UpdateACLToolStripMenuItem.Name = "UpdateACLToolStripMenuItem";
this.UpdateACLToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.UpdateACLToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.UpdateACLToolStripMenuItem.Text = "Update ACL";
this.UpdateACLToolStripMenuItem.Click += new System.EventHandler(this.updateACLToolStripMenuItem_Click);
//
// updateACLWithProxyToolStripMenuItem
//
this.updateACLWithProxyToolStripMenuItem.Name = "updateACLWithProxyToolStripMenuItem";
this.updateACLWithProxyToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.updateACLWithProxyToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.updateACLWithProxyToolStripMenuItem.Text = "Update ACL with proxy";
this.updateACLWithProxyToolStripMenuItem.Click += new System.EventHandler(this.updateACLWithProxyToolStripMenuItem_Click);
//
// updatePACToolStripMenuItem
//
this.updatePACToolStripMenuItem.Name = "updatePACToolStripMenuItem";
this.updatePACToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.updatePACToolStripMenuItem.Text = "Update PAC";
this.updatePACToolStripMenuItem.Click += new System.EventHandler(this.updatePACToolStripMenuItem_Click);
//
// UninstallServiceToolStripMenuItem
//
this.UninstallServiceToolStripMenuItem.Name = "UninstallServiceToolStripMenuItem";
this.UninstallServiceToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.UninstallServiceToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.UninstallServiceToolStripMenuItem.Text = "Uninstall NF Service";
this.UninstallServiceToolStripMenuItem.Click += new System.EventHandler(this.UninstallServiceToolStripMenuItem_Click);
//
// UninstallTapDriverToolStripMenuItem
//
this.UninstallTapDriverToolStripMenuItem.Name = "UninstallTapDriverToolStripMenuItem";
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.UninstallTapDriverToolStripMenuItem.Text = "Uninstall TUN/TAP driver";
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.reinstallTapDriverToolStripMenuItem_Click);
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.UninstallTapDriverToolStripMenuItem_Click);
//
// HelpToolStripMenuItem
//
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.CheckForUpdatesToolStripMenuItem,
this.fAQToolStripMenuItem});
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.CheckForUpdatesToolStripMenuItem, this.fAQToolStripMenuItem
});
this.HelpToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
this.HelpToolStripMenuItem.Name = "HelpToolStripMenuItem";
this.HelpToolStripMenuItem.Size = new System.Drawing.Size(47, 21);
@@ -525,14 +538,10 @@
// StatusStrip
//
this.StatusStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.StatusLabel,
this.UsedBandwidthLabel,
this.DownloadSpeedLabel,
this.UploadSpeedLabel,
this.blankToolStripStatusLabel,
this.NatTypeStatusLabel,
this.NatTypeStatusLightLabel});
this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.StatusLabel, this.UsedBandwidthLabel, this.DownloadSpeedLabel, this.UploadSpeedLabel, this.blankToolStripStatusLabel, this.NatTypeStatusLabel, this.NatTypeStatusLightLabel
});
this.StatusStrip.Location = new System.Drawing.Point(0, 272);
this.StatusStrip.Name = "StatusStrip";
this.StatusStrip.Size = new System.Drawing.Size(740, 22);
@@ -595,7 +604,7 @@
//
// ControlButton
//
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.ControlButton.Location = new System.Drawing.Point(631, 3);
this.ControlButton.Name = "ControlButton";
this.ControlButton.Size = new System.Drawing.Size(75, 27);
@@ -607,7 +616,7 @@
// NotifyIcon
//
this.NotifyIcon.ContextMenuStrip = this.NotifyMenu;
this.NotifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("NotifyIcon.Icon")));
this.NotifyIcon.Icon = ((System.Drawing.Icon) (resources.GetObject("NotifyIcon.Icon")));
this.NotifyIcon.Text = "Netch";
this.NotifyIcon.Visible = true;
this.NotifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.NotifyIcon_MouseDoubleClick);
@@ -615,9 +624,10 @@
// NotifyMenu
//
this.NotifyMenu.ImageScalingSize = new System.Drawing.Size(20, 20);
this.NotifyMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ShowMainFormToolStripButton,
this.ExitToolStripButton});
this.NotifyMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.ShowMainFormToolStripButton, this.ExitToolStripButton
});
this.NotifyMenu.Name = "NotifyMenu";
this.NotifyMenu.ShowItemToolTips = false;
this.NotifyMenu.Size = new System.Drawing.Size(108, 48);
@@ -638,7 +648,7 @@
//
// SettingsButton
//
this.SettingsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.SettingsButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.SettingsButton.Location = new System.Drawing.Point(1, 3);
this.SettingsButton.Name = "SettingsButton";
this.SettingsButton.Size = new System.Drawing.Size(72, 27);
@@ -697,6 +707,13 @@
this.ButtomControlContainerControl.TabStop = false;
this.ButtomControlContainerControl.Text = "groupBox1";
//
// removeNetchFirewallRulesToolStripMenuItem
//
this.removeNetchFirewallRulesToolStripMenuItem.Name = "removeNetchFirewallRulesToolStripMenuItem";
this.removeNetchFirewallRulesToolStripMenuItem.Size = new System.Drawing.Size(243, 22);
this.removeNetchFirewallRulesToolStripMenuItem.Text = "Remove Netch Firewall Rules";
this.removeNetchFirewallRulesToolStripMenuItem.Click += new System.EventHandler(this.RemoveNetchFirewallRulesToolStripMenuItem_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -707,9 +724,9 @@
this.Controls.Add(this.MenuStrip);
this.Controls.Add(this.StatusStrip);
this.Controls.Add(this.flowLayoutPanel1);
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte) (134)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = ((System.Drawing.Icon) (resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.MaximizeBox = false;
this.Name = "MainForm";
@@ -724,13 +741,13 @@
this.configLayoutPanel.ResumeLayout(false);
this.configLayoutPanel.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.EditServerPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.CopyLinkPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.DeleteServerPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize) (this.EditServerPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize) (this.CopyLinkPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize) (this.DeleteServerPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize) (this.SpeedPictureBox)).EndInit();
this.tableLayoutPanel3.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.EditModePictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.DeleteModePictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize) (this.EditModePictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize) (this.DeleteModePictureBox)).EndInit();
this.StatusStrip.ResumeLayout(false);
this.StatusStrip.PerformLayout();
this.NotifyMenu.ResumeLayout(false);
@@ -740,8 +757,8 @@
this.ButtomControlContainerControl.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
private System.Windows.Forms.ToolStripMenuItem removeNetchFirewallRulesToolStripMenuItem;
private System.Windows.Forms.ToolStripButton AboutToolStripButton;
private System.Windows.Forms.ToolStripMenuItem CleanDNSCacheToolStripMenuItem;
@@ -791,6 +808,7 @@
private System.Windows.Forms.ToolStripMenuItem UpdateACLToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem updateACLWithProxyToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem;
private System.Windows.Forms.ToolStripStatusLabel UploadSpeedLabel;
private System.Windows.Forms.ToolStripStatusLabel UsedBandwidthLabel;
private System.Windows.Forms.ToolStripLabel NewVersionLabel;
@@ -803,5 +821,6 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
private System.Windows.Forms.ToolStripMenuItem updatePACToolStripMenuItem;
}
}

View File

@@ -1,344 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Forms.Mode;
using Netch.Models;
using Netch.Utils;
namespace Netch.Forms
{
partial class Dummy
{
}
partial class MainForm
{
#region MenuStrip
#region
private void ImportServersFromClipboardToolStripMenuItem_Click(object sender, EventArgs e)
{
var texts = Clipboard.GetText();
if (!string.IsNullOrWhiteSpace(texts))
{
var servers = ShareLink.ParseText(texts);
Global.Settings.Server.AddRange(servers);
NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", servers.Count));
InitServer();
Configuration.Save();
}
}
private void AddServerToolStripMenuItem_Click(object sender, EventArgs e)
{
var s = ((ToolStripMenuItem) sender).Text;
var start = s.IndexOf("[", StringComparison.Ordinal) + 1;
var end = s.IndexOf("]", start, StringComparison.Ordinal);
var result = s.Substring(start, end - start);
Hide();
ServerHelper.GetUtilByFullName(result).Create();
InitServer();
Configuration.Save();
Show();
}
#endregion
#region
private void CreateProcessModeToolStripButton_Click(object sender, EventArgs e)
{
Hide();
new Process().ShowDialog();
Show();
}
private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
try
{
ModeHelper.Load();
InitMode();
NotifyTip(i18N.Translate("Modes have been reload"));
}
catch (Exception)
{
// ignored
}
finally
{
Enabled = true;
}
}
#endregion
#region
private void ManageSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
{
Hide();
new SubscribeForm().ShowDialog();
InitServer();
Show();
}
private async void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
{
await UpdateServersFromSubscribe();
}
private async Task UpdateServersFromSubscribe()
{
void DisableItems(bool v)
{
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ProfileGroupBox.Enabled = ControlButton.Enabled = v;
}
if (Global.Settings.UseProxyToUpdateSubscription && ServerComboBox.SelectedIndex == -1)
Global.Settings.UseProxyToUpdateSubscription = false;
if (Global.Settings.UseProxyToUpdateSubscription && ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
if (Global.Settings.SubscribeLink.Count <= 0)
{
MessageBoxX.Show(i18N.Translate("No subscription link"));
return;
}
StatusText(i18N.Translate("Starting update subscription"));
DisableItems(false);
var useProxyToUpdateSubscription = Global.Settings.UseProxyToUpdateSubscription;
try
{
string proxyServer = null;
if (useProxyToUpdateSubscription)
{
var mode = new Models.Mode
{
Remark = "ProxyUpdate",
Type = 5
};
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
}
await Subscription.UpdateServersAsync(proxyServer);
InitServer();
Configuration.Save();
StatusText(i18N.Translate("Subscription updated"));
}
catch (Exception)
{
// ignored
}
finally
{
if (useProxyToUpdateSubscription)
{
try
{
await MainController.Stop();
}
catch
{
// ignored
}
}
DisableItems(true);
}
}
#endregion
#region
private void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
void OnNewVersionNotFound(object o, EventArgs args)
{
_updater.NewVersionNotFound -= OnNewVersionNotFound;
NotifyTip(i18N.Translate("Already latest version"));
}
void OnNewVersionFoundFailed(object o, EventArgs args)
{
_updater.NewVersionFoundFailed -= OnNewVersionFoundFailed;
NotifyTip(i18N.Translate("New version found failed"), info: false);
}
_updater.NewVersionNotFound += OnNewVersionNotFound;
_updater.NewVersionFoundFailed += OnNewVersionFoundFailed;
CheckUpdate();
});
}
private void OpenDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
Utils.Utils.Open(".\\");
}
private async void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
await Task.Run(() =>
{
NativeMethods.FlushDNSResolverCache();
DNS.Cache.Clear();
});
StatusText(i18N.Translate("DNS cache cleanup succeeded"));
}
catch (Exception)
{
// ignored
}
}
private void updateACLWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateACL(true);
}
private void updateACLToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateACL(false);
}
private async void UpdateACL(bool useProxy)
{
if (useProxy && ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
Enabled = false;
NotifyTip(i18N.Translate("Updating in the background"));
try
{
if (useProxy)
{
var mode = new Models.Mode
{
Remark = "ProxyUpdate",
Type = 5
};
State = State.Starting;
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
}
var req = WebUtil.CreateRequest(Global.Settings.ACL);
if (useProxy)
req.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
await WebUtil.DownloadFileAsync(req, Path.Combine(Global.NetchDir, "bin\\default.acl"));
NotifyTip(i18N.Translate("ACL updated successfully"));
}
catch (Exception e)
{
NotifyTip(i18N.Translate("ACL update failed") + "\n" + e.Message, info: false);
Logging.Error("更新 ACL 失败!" + e);
}
finally
{
if (useProxy)
{
await MainController.Stop();
State = State.Stopped;
}
Enabled = true;
}
}
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
try
{
await Task.Run(() =>
{
if (NFController.UninstallDriver())
{
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
}
});
}
finally
{
Enabled = true;
}
}
private async void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
{
StatusText(i18N.TranslateFormat("Uninstalling {0}", "TUN/TAP driver"));
Enabled = false;
try
{
await Task.Run(TUNTAP.deltapall);
StatusText(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
}
catch (Exception exception)
{
Logging.Error($"卸载 TUN/TAP 适配器失败: {exception}");
}
finally
{
State = State.Waiting;
Enabled = true;
}
}
#endregion
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Exit(true);
}
private void VersionLabel_Click(object sender, EventArgs e)
{
Utils.Utils.Open($"https://github.com/{UpdateChecker.Owner}/{UpdateChecker.Repo}/releases");
}
private void AboutToolStripButton_Click(object sender, EventArgs e)
{
Hide();
new AboutForm().ShowDialog();
Show();
}
private void fAQToolStripMenuItem_Click(object sender, EventArgs e)
{
Utils.Utils.Open($"https://netch.org/#/docs/zh-CN/faq");
}
#endregion
}
}

View File

@@ -1,106 +0,0 @@
using System;
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;
namespace Netch.Forms
{
/// <summary lang="en">
/// this class is used to disable Designer <para />
/// </summary>
/// <summary lang="zh">
/// 此类用于禁用设计器
/// </summary>
[DesignerCategory("")]
public partial class Dummy
{
}
partial class MainForm
{
private readonly UpdateChecker _updater = new UpdateChecker();
private void CheckUpdate()
{
_updater.NewVersionFound += (o, args) =>
{
NotifyTip($"{i18N.Translate(@"New version available", ": ")}{_updater.LatestVersionNumber}");
NewVersionLabel.Visible = true;
};
_updater.Check(Global.Settings.CheckBetaUpdate);
}
private async void NewVersionLabel_Click(object sender, EventArgs e)
{
if (!_updater.LatestRelease.assets.Any())
{
Utils.Utils.Open(_updater.LatestVersionUrl);
return;
}
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
return;
NotifyTip(i18N.Translate("Start downloading new version"));
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 (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();
}
catch (Exception exception)
{
NotifyTip($"{i18N.Translate("Download update failed")}\n{exception.Message}");
Logging.Error($"下载更新失败 {exception}");
}
void RunUpdater()
{
// if debugging process stopped, debugger will kill child processes!!!!
// 调试进程结束,调试器将会杀死子进程
// uncomment if(!Debugger.isAttach) block in NetchUpdater Project's main() method and attach to NetchUpdater process to debug
// 在 NetchUpdater 项目的 main() 方法中取消注释 if!Debugger.isAttach并附加到 NetchUpdater 进程进行调试
Process.Start(new ProcessStartInfo
{
FileName = Path.Combine(Global.NetchDir, "NetchUpdater.exe"),
Arguments =
$"{Global.Settings.UDPSocketPort} \"{fileFullPath}\" \"{Global.NetchDir}\""
});
}
}
}
}

View File

@@ -1,187 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Models;
using Netch.Utils;
namespace Netch.Forms
{
public partial class Dummy
{
}
partial class MainForm
{
private int _configurationGroupBoxHeight;
private int _profileConfigurationHeight;
private void InitProfile()
{
// Clear
foreach (var button in ProfileButtons)
button.Dispose();
ProfileButtons.Clear();
ProfileTable.ColumnStyles.Clear();
ProfileTable.RowStyles.Clear();
var numProfile = Global.Settings.ProfileCount;
if (numProfile == 0)
{
// Hide Profile GroupBox, Change window size
configLayoutPanel.RowStyles[2].SizeType = SizeType.Percent;
configLayoutPanel.RowStyles[2].Height = 0;
ProfileGroupBox.Visible = false;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight - _profileConfigurationHeight);
}
else
{
// Load Profiles
ProfileTable.ColumnCount = numProfile;
while (Global.Settings.Profiles.Count < numProfile)
{
Global.Settings.Profiles.Add(new Profile());
}
for (var i = 0; i < numProfile; ++i)
{
var b = new Button();
b.Click += ProfileButton_Click;
b.Dock = DockStyle.Fill;
b.Text = !Global.Settings.Profiles[i].IsDummy ? Global.Settings.Profiles[i].ProfileName : i18N.Translate("None");
ProfileTable.Controls.Add(b, i, 0);
ProfileButtons.Add(b);
}
// equal column
for (var i = 1; i <= ProfileTable.RowCount; i++)
{
ProfileTable.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
}
for (var i = 1; i <= ProfileTable.ColumnCount; i++)
{
ProfileTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
}
configLayoutPanel.RowStyles[2].SizeType = SizeType.AutoSize;
ProfileGroupBox.Visible = true;
ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight);
}
}
private void LoadProfile(int index)
{
var p = Global.Settings.Profiles[index];
ProfileNameText.Text = p.ProfileName;
ModeComboBox.ResetCompletionList();
if (p.IsDummy)
throw new Exception("Profile not found.");
var server = ServerComboBox.Items.Cast<Server>().FirstOrDefault(s => s.Remark.Equals(p.ServerRemark));
var mode = ModeComboBox.Items.Cast<Models.Mode>().FirstOrDefault(m => m.Remark.Equals(p.ModeRemark));
if (server == null)
{
throw new Exception("Server not found.");
}
if (mode == null)
{
throw new Exception("Mode not found.");
}
ServerComboBox.SelectedItem = server;
ModeComboBox.SelectedItem = mode;
}
private void SaveProfile(int index)
{
var selectedServer = (Server) ServerComboBox.SelectedItem;
var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
var name = ProfileNameText.Text;
Global.Settings.Profiles[index] = new Profile(selectedServer, selectedMode, name);
}
private void RemoveProfile(int index)
{
Global.Settings.Profiles[index] = new Profile();
}
private List<Button> ProfileButtons = new List<Button>();
private async void ProfileButton_Click(object sender, EventArgs e)
{
var index = ProfileButtons.IndexOf((Button) sender);
if (ModifierKeys == Keys.Control)
{
if (ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
}
else if (ModeComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
}
else if (ProfileNameText.Text == "")
{
MessageBoxX.Show(i18N.Translate("Please enter a profile name first"));
}
else
{
SaveProfile(index);
ProfileButtons[index].Text = ProfileNameText.Text;
}
return;
}
if (Global.Settings.Profiles[index].IsDummy)
{
MessageBoxX.Show(
i18N.Translate("No saved profile here. Save a profile first by Ctrl+Click on the button"));
return;
}
if (ModifierKeys == Keys.Shift)
{
if (MessageBoxX.Show(i18N.Translate("Remove this Profile?"), confirm: true) != DialogResult.OK) return;
RemoveProfile(index);
ProfileButtons[index].Text = i18N.Translate("None");
return;
}
try
{
LoadProfile(index);
}
catch (Exception exception)
{
MessageBoxX.Show(exception.Message, LogLevel.ERROR);
return;
}
// start the profile
ControlFun();
if (State == State.Stopping || State == State.Stopped)
{
while (State != State.Stopped)
{
await Task.Delay(250);
}
ControlFun();
}
}
}
}

View File

@@ -1,175 +0,0 @@
using System;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Utils;
namespace Netch.Forms
{
public partial class Dummy
{
}
partial class MainForm
{
#region Server
private void InitServer()
{
var comboBoxInitialized = _comboBoxInitialized;
_comboBoxInitialized = false;
ServerComboBox.Items.Clear();
ServerComboBox.Items.AddRange(Global.Settings.Server.ToArray());
SelectLastServer();
_comboBoxInitialized = comboBoxInitialized;
}
private static void TestServer()
{
try
{
Parallel.ForEach(Global.Settings.Server, new ParallelOptions {MaxDegreeOfParallelism = 16},
server => { server.Test(); });
}
catch (Exception)
{
// ignored
}
}
public void SelectLastServer()
{
// 如果值合法,选中该位置
if (Global.Settings.ServerComboBoxSelectedIndex > 0 &&
Global.Settings.ServerComboBoxSelectedIndex < ServerComboBox.Items.Count)
{
ServerComboBox.SelectedIndex = Global.Settings.ServerComboBoxSelectedIndex;
}
// 如果值非法,且当前 ServerComboBox 中有元素,选择第一个位置
else if (ServerComboBox.Items.Count > 0)
{
ServerComboBox.SelectedIndex = 0;
}
// 如果当前 ServerComboBox 中没元素,不做处理
}
#endregion
#region Mode
public void InitMode()
{
var comboBoxInitialized = _comboBoxInitialized;
_comboBoxInitialized = false;
ModeComboBox.Items.Clear();
ModeComboBox.Items.AddRange(Global.Modes.ToArray());
ModeComboBox.Tag = null;
SelectLastMode();
_comboBoxInitialized = comboBoxInitialized;
}
public void SelectLastMode()
{
// 如果值合法,选中该位置
if (Global.Settings.ModeComboBoxSelectedIndex > 0 &&
Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
{
ModeComboBox.SelectedIndex = Global.Settings.ModeComboBoxSelectedIndex;
}
// 如果值非法,且当前 ModeComboBox 中有元素,选择第一个位置
else if (ModeComboBox.Items.Count > 0)
{
ModeComboBox.SelectedIndex = 0;
}
// 如果当前 ModeComboBox 中没元素,不做处理
}
#endregion
/// <summary>
/// Init at <see cref="MainForm_Load"/>
/// </summary>
private int _eWidth;
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
try
{
if (!(sender is ComboBox cbx))
{
return;
}
// 绘制背景颜色
e.Graphics.FillRectangle(new SolidBrush(Color.White), e.Bounds);
if (e.Index < 0) return;
// 绘制 备注/名称 字符串
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, new SolidBrush(Color.Black), e.Bounds);
switch (cbx.Items[e.Index])
{
case Models.Server item:
{
// 计算延迟底色
SolidBrush brush;
if (item.Delay > 200)
brush = new SolidBrush(Color.Red);
else if (item.Delay > 80)
brush = new SolidBrush(Color.Yellow);
else if (item.Delay >= 0)
brush = new SolidBrush(Color.FromArgb(50, 255, 56));
else
brush = new SolidBrush(Color.Gray);
// 绘制延迟底色
e.Graphics.FillRectangle(brush, _eWidth * 9, e.Bounds.Y, _eWidth, e.Bounds.Height);
// 绘制延迟字符串
e.Graphics.DrawString(item.Delay.ToString(), cbx.Font, new SolidBrush(Color.Black),
_eWidth * 9 + _eWidth / 30, e.Bounds.Y);
break;
}
case Models.Mode item:
{
// 绘制 模式Box 底色
e.Graphics.FillRectangle(new SolidBrush(Color.Gray), _eWidth * 9, e.Bounds.Y, _eWidth,
e.Bounds.Height);
// 绘制 模式行数 字符串
e.Graphics.DrawString(item.Rule.Count.ToString(), cbx.Font, new SolidBrush(Color.Black),
_eWidth * 9 + _eWidth / 30, e.Bounds.Y);
break;
}
}
}
catch (Exception)
{
// ignored
}
}
private void AddAddServerToolStripMenuItems()
{
foreach (var serversUtil in ServerHelper.ServerUtils.Where(i => !string.IsNullOrEmpty(i.FullName)))
{
var fullName = serversUtil.FullName;
var control = new ToolStripMenuItem
{
Name = $"Add{fullName}ServerToolStripMenuItem",
Size = new Size(259, 22),
Text = i18N.TranslateFormat("Add [{0}] Server", fullName),
};
_mainFormText.Add(control.Name, new[] {"Add [{0}] Server", fullName});
control.Click += AddServerToolStripMenuItem_Click;
ServerToolStripMenuItem.DropDownItems.Add(control);
}
}
}
}

View File

@@ -1,233 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Netch.Models;
using Netch.Utils;
namespace Netch.Forms
{
public partial class Dummy
{
}
partial class MainForm
{
private bool IsWaiting => State == State.Waiting || State == State.Stopped;
private State _state = State.Waiting;
/// <summary>
/// 当前状态
/// </summary>
public State State
{
get => _state;
private set
{
void StartDisableItems(bool enabled)
{
ServerComboBox.Enabled =
ModeComboBox.Enabled =
EditModePictureBox.Enabled =
EditServerPictureBox.Enabled =
DeleteModePictureBox.Enabled =
DeleteServerPictureBox.Enabled = enabled;
// 启动需要禁用的控件
UninstallServiceToolStripMenuItem.Enabled =
UpdateACLToolStripMenuItem.Enabled =
updateACLWithProxyToolStripMenuItem.Enabled =
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
UninstallTapDriverToolStripMenuItem.Enabled =
ReloadModesToolStripMenuItem.Enabled = enabled;
}
_state = value;
StatusText(i18N.Translate(StateExtension.GetStatusString(value)));
switch (value)
{
case State.Waiting:
ControlButton.Enabled = true;
ControlButton.Text = i18N.Translate("Start");
break;
case State.Starting:
ControlButton.Enabled = false;
ControlButton.Text = "...";
ProfileGroupBox.Enabled = false;
StartDisableItems(false);
break;
case State.Started:
ControlButton.Enabled = true;
ControlButton.Text = i18N.Translate("Stop");
StatusTextAppend(StatusPortInfoText.Value);
ProfileGroupBox.Enabled = true;
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = Global.Flags.IsWindows10Upper;
break;
case State.Stopping:
ControlButton.Enabled = false;
ControlButton.Text = "...";
ProfileGroupBox.Enabled = false;
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = false;
NatTypeStatusText();
break;
case State.Stopped:
ControlButton.Enabled = true;
ControlButton.Text = i18N.Translate("Start");
LastUploadBandwidth = 0;
LastDownloadBandwidth = 0;
Bandwidth.Stop();
ProfileGroupBox.Enabled = true;
StartDisableItems(true);
break;
case State.Terminating:
Dispose();
Environment.Exit(Environment.ExitCode);
return;
}
}
}
public void NatTypeStatusText(string text = "", string country = "")
{
if (InvokeRequired)
{
BeginInvoke(new Action<string, string>(NatTypeStatusText), text, country);
return;
}
if (State != State.Started)
{
NatTypeStatusLabel.Text = "";
NatTypeStatusLabel.Visible = NatTypeStatusLightLabel.Visible = false;
return;
}
if (!string.IsNullOrEmpty(text))
{
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} {(country != string.Empty ? $"[{country}]" : "")}";
UpdateNatTypeLight(int.TryParse(text, out var natType) ? natType : -1);
}
else
{
NatTypeStatusLabel.Text = $@"NAT{i18N.Translate(": ", "Test failed")}";
}
NatTypeStatusLabel.Visible = true;
}
/// <summary>
/// 更新 NAT指示灯颜色
/// </summary>
/// <param name="natType"></param>
private void UpdateNatTypeLight(int natType = -1)
{
if (natType > 0 && natType < 5)
{
NatTypeStatusLightLabel.Visible = Global.Flags.IsWindows10Upper;
Color c;
switch (natType)
{
case 1:
c = Color.LimeGreen;
break;
case 2:
c = Color.Yellow;
break;
case 3:
c = Color.Red;
break;
case 4:
c = Color.Black;
break;
default:
c = Color.Black;
break;
}
NatTypeStatusLightLabel.ForeColor = c;
}
else
{
NatTypeStatusLightLabel.Visible = false;
}
}
/// <summary>
/// 更新状态栏文本
/// </summary>
/// <param name="text"></param>
public void StatusText(string text)
{
if (InvokeRequired)
{
BeginInvoke(new Action<string>(StatusText), text);
return;
}
StatusLabel.Text = i18N.Translate("Status", ": ") + text;
}
public void StatusTextAppend(string text)
{
StatusLabel.Text += text;
}
public static class StatusPortInfoText
{
private static ushort? _socks5Port;
private static ushort? _httpPort;
private static bool _shareLan;
public static ushort HttpPort
{
set => _httpPort = value;
}
public static ushort Socks5Port
{
set => _socks5Port = value;
}
public static void UpdateShareLan() => _shareLan = Global.Settings.LocalAddress != "127.0.0.1";
public static string Value
{
get
{
var strings = new List<string>();
if (_socks5Port != null)
{
strings.Add($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
}
if (_httpPort != null)
{
strings.Add($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
}
if (!strings.Any())
return string.Empty;
return $" ({(_shareLan ? i18N.Translate("Allow other Devices to connect") + " " : "")}{string.Join(" | ", strings)})";
}
}
public static void Reset()
{
_httpPort = _socks5Port = null;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,11 @@
using System;
using System.Windows.Forms;
using Netch.Models;
using Netch.Utils;
namespace Netch.Utils
namespace Netch.Forms
{
static class MessageBoxX
public static class MessageBoxX
{
/// <summary>
/// </summary>
@@ -34,11 +35,11 @@ namespace Netch.Utils
};
return MessageBox.Show(
owner: owner,
text: text,
caption: i18N.Translate(title),
buttons: confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK,
icon: msgIcon);
owner,
text,
i18N.Translate(title),
confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK,
msgIcon);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,20 @@
using Netch.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Utils;
namespace Netch.Forms
{
public partial class SettingForm : Form
{
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new();
private readonly Dictionary<Control, Action<Control>> _saveActions = new();
public SettingForm()
{
InitializeComponent();
@@ -20,7 +22,6 @@ namespace Netch.Forms
InitValue();
}
private void SettingForm_Load(object sender, EventArgs e)
{
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
@@ -59,17 +60,26 @@ namespace Netch.Forms
c => Global.Settings.ResolveServerHostname = c,
Global.Settings.ResolveServerHostname);
BindRadioBox(ICMPingRadioBtn,
_ => { },
!Global.Settings.ServerTCPing);
BindRadioBox(TCPingRadioBtn,
c => Global.Settings.ServerTCPing = c,
Global.Settings.ServerTCPing);
BindTextBox<int>(ProfileCountTextBox,
i => i > -1,
i => Global.Settings.ProfileCount = i,
Global.Settings.ProfileCount);
BindCheckBox(TcpingAtStartedCheckBox,
b => Global.Settings.StartedTcping = b,
Global.Settings.StartedTcping);
BindTextBox<int>(DetectionIntervalTextBox,
i => i >= 0,
i => Global.Settings.StartedTcping_Interval = i,
Global.Settings.StartedTcping_Interval);
BindTextBox<int>(DetectionTickTextBox,
i => ServerHelper.DelayTestHelper.Range.InRange(i),
i => Global.Settings.DetectionTick = i,
Global.Settings.DetectionTick);
BindTextBox<int>(StartedPingIntervalTextBox,
_ => true,
i => Global.Settings.StartedPingInterval = i,
Global.Settings.StartedPingInterval);
InitSTUN();
@@ -90,8 +100,6 @@ namespace Netch.Forms
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,
@@ -105,6 +113,10 @@ namespace Netch.Forms
s => Global.Settings.ProcessNoProxyForUdp = s,
Global.Settings.ProcessNoProxyForUdp);
BindCheckBox(NoProxyForTcpCheckBox,
s => Global.Settings.ProcessNoProxyForTcp = s,
Global.Settings.ProcessNoProxyForTcp);
#endregion
#region TUN/TAP
@@ -124,7 +136,6 @@ namespace Netch.Forms
BindCheckBox(UseCustomDNSCheckBox,
b => { Global.Settings.TUNTAP.UseCustomDNS = b; },
Global.Settings.TUNTAP.UseCustomDNS);
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
BindTextBox(TUNTAPDNSTextBox,
s => !UseCustomDNSCheckBox.Checked || DNS.TrySplit(s, out _, 2),
@@ -160,6 +171,10 @@ namespace Netch.Forms
#region V2Ray
BindCheckBox(XrayConeCheckBox,
b => Global.Settings.V2RayConfig.XrayCone = b,
Global.Settings.V2RayConfig.XrayCone);
BindCheckBox(TLSAllowInsecureCheckBox,
b => Global.Settings.V2RayConfig.AllowInsecure = b,
Global.Settings.V2RayConfig.AllowInsecure);
@@ -227,9 +242,9 @@ namespace Netch.Forms
b => Global.Settings.CheckBetaUpdate = b,
Global.Settings.CheckBetaUpdate);
BindCheckBox(UpdateSubscribeatWhenOpenedCheckBox,
b => Global.Settings.UpdateSubscribeatWhenOpened = b,
Global.Settings.UpdateSubscribeatWhenOpened);
BindCheckBox(UpdateServersWhenOpenedCheckBox,
b => Global.Settings.UpdateServersWhenOpened = b,
Global.Settings.UpdateServersWhenOpened);
#endregion
@@ -255,21 +270,14 @@ namespace Netch.Forms
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
{
TUNTAPDNSTextBox.Enabled = UseCustomDNSCheckBox.Checked;
if (UseCustomDNSCheckBox.Checked)
{
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
? DNS.Join(Global.Settings.TUNTAP.DNS)
: "1.1.1.1";
}
else
{
TUNTAPDNSTextBox.Text = "AioDNS";
}
}
private void InitSTUN()
{
try
@@ -306,14 +314,13 @@ namespace Netch.Forms
}
if (!flag)
{
return;
}
#endregion
#region CheckSTUN
var stunFlag = true;
var errFlag = false;
var stunServer = string.Empty;
ushort stunServerPort = 3478;
@@ -324,16 +331,14 @@ namespace Netch.Forms
stunServer = stun[0];
if (stun.Length > 1)
if (!ushort.TryParse(stun[1], out stunServerPort))
{
stunFlag = false;
}
errFlag = true;
}
else
{
stunFlag = false;
errFlag = true;
}
if (!stunFlag)
if (errFlag)
{
Utils.Utils.ChangeControlForeColor(STUN_ServerComboBox, Color.Red);
return;
@@ -341,14 +346,10 @@ namespace Netch.Forms
#endregion
#endregion
#region Save
foreach (var pair in _saveActions)
{
pair.Value.Invoke(pair.Key);
}
Global.Settings.STUN_Server = stunServer;
Global.Settings.STUN_Server_Port = stunServerPort;
@@ -417,17 +418,22 @@ namespace Netch.Forms
private void BindCheckBox(CheckBox control, Action<bool> save, bool value)
{
control.Checked = value;
_checkActions.Add(control, s => true);
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
}
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
private readonly Dictionary<Control, Action<Control>> _saveActions = new Dictionary<Control, Action<Control>>();
private void ModifySystemDNSCheckBox_CheckedChanged(object sender, EventArgs e)
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
{
ModifiedDNSTextBox.Enabled = ModifySystemDNSCheckBox.Checked;
control.Checked = value;
_saveActions.Add(control, c => save.Invoke(((RadioButton) c).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;
}
}
}

View File

@@ -32,7 +32,7 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SubscribeForm));
this.AddSubscriptionBox = new System.Windows.Forms.GroupBox();
this.UserAgentTextBox = new System.Windows.Forms.TextBox();
this.ClearButton = new System.Windows.Forms.Button();
this.UnselectButton = new System.Windows.Forms.Button();
this.AddButton = new System.Windows.Forms.Button();
this.UserAgentLabel = new System.Windows.Forms.Label();
this.LinkTextBox = new System.Windows.Forms.TextBox();
@@ -40,25 +40,24 @@
this.RemarkTextBox = new System.Windows.Forms.TextBox();
this.RemarkLabel = new System.Windows.Forms.Label();
this.SubscribeLinkListView = new System.Windows.Forms.ListView();
this.EnableColumnHeader = new System.Windows.Forms.ColumnHeader();
this.RemarkColumnHeader = new System.Windows.Forms.ColumnHeader();
this.LinkColumnHeader = new System.Windows.Forms.ColumnHeader();
this.UserAgentHeader = new System.Windows.Forms.ColumnHeader();
this.pContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.deleteServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.CopyLinkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UseSelectedServerCheckBox = new System.Windows.Forms.CheckBox();
this.MainTableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
this.ControlsPanel = new System.Windows.Forms.Panel();
this.AddSubscriptionBox.SuspendLayout();
this.pContextMenuStrip.SuspendLayout();
this.MainTableLayoutPanel.SuspendLayout();
this.ControlsPanel.SuspendLayout();
this.SuspendLayout();
//
// AddSubscriptionBox
//
this.AddSubscriptionBox.Controls.Add(this.UserAgentTextBox);
this.AddSubscriptionBox.Controls.Add(this.ClearButton);
this.AddSubscriptionBox.Controls.Add(this.UnselectButton);
this.AddSubscriptionBox.Controls.Add(this.AddButton);
this.AddSubscriptionBox.Controls.Add(this.UserAgentLabel);
this.AddSubscriptionBox.Controls.Add(this.LinkTextBox);
@@ -66,9 +65,9 @@
this.AddSubscriptionBox.Controls.Add(this.RemarkTextBox);
this.AddSubscriptionBox.Controls.Add(this.RemarkLabel);
this.AddSubscriptionBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.AddSubscriptionBox.Location = new System.Drawing.Point(8, 214);
this.AddSubscriptionBox.Location = new System.Drawing.Point(8, 248);
this.AddSubscriptionBox.Name = "AddSubscriptionBox";
this.AddSubscriptionBox.Size = new System.Drawing.Size(668, 141);
this.AddSubscriptionBox.Size = new System.Drawing.Size(668, 135);
this.AddSubscriptionBox.TabIndex = 1;
this.AddSubscriptionBox.TabStop = false;
//
@@ -79,15 +78,15 @@
this.UserAgentTextBox.Size = new System.Drawing.Size(545, 23);
this.UserAgentTextBox.TabIndex = 6;
//
// ClearButton
// UnselectButton
//
this.ClearButton.Location = new System.Drawing.Point(448, 103);
this.ClearButton.Name = "ClearButton";
this.ClearButton.Size = new System.Drawing.Size(87, 26);
this.ClearButton.TabIndex = 7;
this.ClearButton.Text = "Unselect";
this.ClearButton.UseVisualStyleBackColor = true;
this.ClearButton.Click += new System.EventHandler(this.ClearButton_Click);
this.UnselectButton.Location = new System.Drawing.Point(448, 103);
this.UnselectButton.Name = "UnselectButton";
this.UnselectButton.Size = new System.Drawing.Size(87, 26);
this.UnselectButton.TabIndex = 7;
this.UnselectButton.Text = "Unselect";
this.UnselectButton.UseVisualStyleBackColor = true;
this.UnselectButton.Click += new System.EventHandler(this.UnselectButton_Click);
//
// AddButton
//
@@ -95,7 +94,7 @@
this.AddButton.Name = "AddButton";
this.AddButton.Size = new System.Drawing.Size(113, 26);
this.AddButton.TabIndex = 7;
this.AddButton.Text = "Add / Modify";
this.AddButton.Text = "Add";
this.AddButton.UseVisualStyleBackColor = true;
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
//
@@ -143,19 +142,29 @@
// SubscribeLinkListView
//
this.SubscribeLinkListView.AllowColumnReorder = true;
this.SubscribeLinkListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {this.RemarkColumnHeader, this.LinkColumnHeader, this.UserAgentHeader});
this.SubscribeLinkListView.CheckBoxes = true;
this.SubscribeLinkListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[]
{
this.EnableColumnHeader, this.RemarkColumnHeader, this.LinkColumnHeader, this.UserAgentHeader
});
this.SubscribeLinkListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.SubscribeLinkListView.FullRowSelect = true;
this.SubscribeLinkListView.HideSelection = false;
this.SubscribeLinkListView.Location = new System.Drawing.Point(8, 8);
this.SubscribeLinkListView.MultiSelect = false;
this.SubscribeLinkListView.Name = "SubscribeLinkListView";
this.SubscribeLinkListView.Size = new System.Drawing.Size(668, 200);
this.SubscribeLinkListView.Size = new System.Drawing.Size(668, 234);
this.SubscribeLinkListView.TabIndex = 0;
this.SubscribeLinkListView.UseCompatibleStateImageBehavior = false;
this.SubscribeLinkListView.View = System.Windows.Forms.View.Details;
this.SubscribeLinkListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.SubscribeLinkListView_ItemChecked);
this.SubscribeLinkListView.SelectedIndexChanged += new System.EventHandler(this.SubscribeLinkListView_SelectedIndexChanged);
this.SubscribeLinkListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.SubscribeLinkListView_MouseUp);
//
// EnableColumnHeader
//
this.EnableColumnHeader.Text = "Status";
//
// RemarkColumnHeader
//
this.RemarkColumnHeader.Text = "Remark";
@@ -164,7 +173,7 @@
// LinkColumnHeader
//
this.LinkColumnHeader.Text = "Link";
this.LinkColumnHeader.Width = 400;
this.LinkColumnHeader.Width = 364;
//
// UserAgentHeader
//
@@ -173,62 +182,51 @@
//
// pContextMenuStrip
//
this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.DeleteToolStripMenuItem, this.CopyLinkToolStripMenuItem});
this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
{
this.DeleteToolStripMenuItem, this.deleteServerToolStripMenuItem, this.CopyLinkToolStripMenuItem
});
this.pContextMenuStrip.Name = "pContextMenuStrip";
this.pContextMenuStrip.Size = new System.Drawing.Size(130, 48);
this.pContextMenuStrip.Size = new System.Drawing.Size(151, 70);
//
// DeleteToolStripMenuItem
//
this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
this.DeleteToolStripMenuItem.Text = "Delete";
this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click);
//
// deleteServerToolStripMenuItem
//
this.deleteServerToolStripMenuItem.Name = "deleteServerToolStripMenuItem";
this.deleteServerToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
this.deleteServerToolStripMenuItem.Text = "DeleteServer";
this.deleteServerToolStripMenuItem.Click += new System.EventHandler(this.deleteServerToolStripMenuItem_Click);
//
// CopyLinkToolStripMenuItem
//
this.CopyLinkToolStripMenuItem.Name = "CopyLinkToolStripMenuItem";
this.CopyLinkToolStripMenuItem.Size = new System.Drawing.Size(129, 22);
this.CopyLinkToolStripMenuItem.Size = new System.Drawing.Size(150, 22);
this.CopyLinkToolStripMenuItem.Text = "CopyLink";
this.CopyLinkToolStripMenuItem.Click += new System.EventHandler(this.CopyLinkToolStripMenuItem_Click);
//
// UseSelectedServerCheckBox
//
this.UseSelectedServerCheckBox.AutoSize = true;
this.UseSelectedServerCheckBox.Location = new System.Drawing.Point(3, 4);
this.UseSelectedServerCheckBox.Name = "UseSelectedServerCheckBox";
this.UseSelectedServerCheckBox.Size = new System.Drawing.Size(285, 21);
this.UseSelectedServerCheckBox.TabIndex = 9;
this.UseSelectedServerCheckBox.Text = "Use Selected Server To Update Subscription";
this.UseSelectedServerCheckBox.UseVisualStyleBackColor = true;
//
// MainTableLayoutPanel
//
this.MainTableLayoutPanel.ColumnCount = 1;
this.MainTableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.MainTableLayoutPanel.Controls.Add(this.SubscribeLinkListView, 0, 0);
this.MainTableLayoutPanel.Controls.Add(this.AddSubscriptionBox, 0, 1);
this.MainTableLayoutPanel.Controls.Add(this.ControlsPanel, 0, 2);
this.MainTableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.MainTableLayoutPanel.Location = new System.Drawing.Point(0, 0);
this.MainTableLayoutPanel.Name = "MainTableLayoutPanel";
this.MainTableLayoutPanel.Padding = new System.Windows.Forms.Padding(5);
this.MainTableLayoutPanel.RowCount = 3;
this.MainTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 58.35777F));
this.MainTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 41.64223F));
this.MainTableLayoutPanel.RowCount = 2;
this.MainTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 62.99213F));
this.MainTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 37.00787F));
this.MainTableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27F));
this.MainTableLayoutPanel.Size = new System.Drawing.Size(684, 391);
this.MainTableLayoutPanel.TabIndex = 11;
//
// ControlsPanel
//
this.ControlsPanel.Controls.Add(this.UseSelectedServerCheckBox);
this.ControlsPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.ControlsPanel.Location = new System.Drawing.Point(5, 358);
this.ControlsPanel.Margin = new System.Windows.Forms.Padding(0);
this.ControlsPanel.Name = "ControlsPanel";
this.ControlsPanel.Size = new System.Drawing.Size(674, 28);
this.ControlsPanel.TabIndex = 2;
//
// SubscribeForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -244,19 +242,16 @@
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Subscribe";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SubscribeForm_FormClosing);
this.Load += new System.EventHandler(this.SubscribeForm_Load);
this.AddSubscriptionBox.ResumeLayout(false);
this.AddSubscriptionBox.PerformLayout();
this.pContextMenuStrip.ResumeLayout(false);
this.MainTableLayoutPanel.ResumeLayout(false);
this.ControlsPanel.ResumeLayout(false);
this.ControlsPanel.PerformLayout();
this.ResumeLayout(false);
}
private System.Windows.Forms.ColumnHeader EnableColumnHeader;
private System.Windows.Forms.Panel ControlsPanel;
private System.Windows.Forms.TableLayoutPanel MainTableLayoutPanel;
private System.Windows.Forms.Button ClearButton;
private System.Windows.Forms.Button UnselectButton;
private System.Windows.Forms.GroupBox AddSubscriptionBox;
private System.Windows.Forms.Label RemarkLabel;
private System.Windows.Forms.TextBox LinkTextBox;
@@ -272,8 +267,9 @@
private System.Windows.Forms.Label UserAgentLabel;
private System.Windows.Forms.TextBox UserAgentTextBox;
private System.Windows.Forms.ColumnHeader UserAgentHeader;
private System.Windows.Forms.CheckBox UseSelectedServerCheckBox;
#endregion
private System.Windows.Forms.ToolStripMenuItem deleteServerToolStripMenuItem;
}
}

View File

@@ -8,85 +8,65 @@ namespace Netch.Forms
{
public partial class SubscribeForm : Form
{
private int _editingIndex = -1;
public SubscribeForm()
{
InitializeComponent();
}
public void InitSubscribeLink()
{
SubscribeLinkListView.Items.Clear();
foreach (var item in Global.Settings.SubscribeLink)
{
SubscribeLinkListView.Items.Add(new ListViewItem(new[]
{
item.Remark,
item.Link,
!string.IsNullOrEmpty(item.UserAgent) ? item.UserAgent : WebUtil.DefaultUserAgent
}));
}
}
private void SubscribeForm_Load(object sender, EventArgs e)
{
i18N.TranslateForm(this);
i18N.TranslateForm(pContextMenuStrip);
ResetEditingGroup();
if (Global.Settings.Server.Count > 0)
{
UseSelectedServerCheckBox.Enabled = true;
UseSelectedServerCheckBox.Checked = Global.Settings.UseProxyToUpdateSubscription;
}
else
{
UseSelectedServerCheckBox.Checked = false;
UseSelectedServerCheckBox.Enabled = false;
}
InitSubscribeLink();
}
private int SelectedIndex
{
get
{
if (SubscribeLinkListView.MultiSelect)
throw new Exception();
return SubscribeLinkListView.SelectedIndices.Count == 0 ? -1 : SubscribeLinkListView.SelectedIndices[0];
}
}
#region EventHandler
private void SubscribeLinkListView_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
if (SelectedIndex != -1)
pContextMenuStrip.Show(SubscribeLinkListView, e.Location);
}
/// <summary>
/// 选中/取消选中
/// </summary>
private void SubscribeLinkListView_SelectedIndexChanged(object sender, EventArgs e)
{
SetEditingGroup(SelectedIndex);
}
/// <summary>
/// 订阅启/禁用
/// </summary>
private void SubscribeLinkListView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
var index = e.Item.Index;
Global.Settings.SubscribeLink[index].Enable = SubscribeLinkListView.Items[index].Checked;
}
private void SubscribeForm_FormClosing(object sender, FormClosingEventArgs e)
{
Configuration.Save();
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
}
private void CopyLinkToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SubscribeLinkListView.SelectedItems.Count > 0)
{
for (var i = SubscribeLinkListView.SelectedItems.Count - 1; i >= 0; i--)
{
var item = SubscribeLinkListView.SelectedItems[i];
var link = Global.Settings.SubscribeLink[item.Index];
Clipboard.SetText(link.Link);
}
}
}
#endregion
private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
{
if (MessageBoxX.Show(i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), confirm: true) == DialogResult.OK)
{
if (SubscribeLinkListView.SelectedItems.Count > 0)
{
for (var i = SubscribeLinkListView.SelectedItems.Count - 1; i >= 0; i--)
{
var item = SubscribeLinkListView.SelectedItems[i];
#region EditBox
DeleteServersInGroup(item.SubItems[0].Text);
Global.Settings.SubscribeLink.RemoveAt(item.Index);
SubscribeLinkListView.Items.Remove(item);
ResetEditingGroup();
}
}
}
private void UnselectButton_Click(object sender, EventArgs e)
{
ResetEditingGroup();
}
private void AddButton_Click(object sender, EventArgs e)
@@ -109,7 +89,7 @@ namespace Netch.Forms
return;
}
if (_editingIndex == -1)
if (SelectedIndex == -1)
{
if (Global.Settings.SubscribeLink.Any(link => link.Remark.Equals(RemarkTextBox.Text)))
{
@@ -119,6 +99,7 @@ namespace Netch.Forms
Global.Settings.SubscribeLink.Add(new SubscribeLink
{
Enable = true,
Remark = RemarkTextBox.Text,
Link = LinkTextBox.Text,
UserAgent = UserAgentTextBox.Text
@@ -126,114 +107,107 @@ namespace Netch.Forms
}
else
{
var target = Global.Settings.SubscribeLink[_editingIndex];
if (MessageBox.Show(i18N.Translate("Delete the corresponding group of items in the server list?"), i18N.Translate("Confirm"), MessageBoxButtons.YesNo) == DialogResult.Yes)
{
DeleteServersInGroup(target.Remark);
}
else
{
RenameServersGroup(target.Remark, RemarkTextBox.Text);
}
var subscribeLink = Global.Settings.SubscribeLink[SelectedIndex];
target.Link = LinkTextBox.Text;
target.Remark = RemarkTextBox.Text;
target.UserAgent = UserAgentTextBox.Text;
RenameServers(subscribeLink.Remark, RemarkTextBox.Text);
subscribeLink.Link = LinkTextBox.Text;
subscribeLink.Remark = RemarkTextBox.Text;
subscribeLink.UserAgent = UserAgentTextBox.Text;
}
Configuration.Save();
Global.Settings.UseProxyToUpdateSubscription = UseSelectedServerCheckBox.Checked;
// MessageBoxX.Show(i18N.Translate("Saved"));
ResetEditingGroup();
MessageBoxX.Show(i18N.Translate("Saved"));
InitSubscribeLink();
}
private static void DeleteServersInGroup(string group)
#endregion
#region ContextMenu
private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
{
if (MessageBoxX.Show(i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), confirm: true) != DialogResult.OK)
return;
var subscribeLink = Global.Settings.SubscribeLink[SelectedIndex];
DeleteServers(subscribeLink.Remark);
Global.Settings.SubscribeLink.Remove(subscribeLink);
InitSubscribeLink();
}
private void deleteServerToolStripMenuItem_Click(object sender, EventArgs e)
{
if (MessageBoxX.Show(i18N.Translate("Confirm deletion?"), confirm: true) != DialogResult.OK)
return;
DeleteServers(Global.Settings.SubscribeLink[SelectedIndex].Remark);
}
private void CopyLinkToolStripMenuItem_Click(object sender, EventArgs e)
{
Clipboard.SetText(Global.Settings.SubscribeLink[SelectedIndex].Link);
}
#endregion
#region Helper
private static void DeleteServers(string group)
{
Global.Settings.Server.RemoveAll(server => server.Group == group);
}
private static void RenameServersGroup(string oldGroup, string newGroup)
private static void RenameServers(string oldGroup, string newGroup)
{
foreach (var server in Global.Settings.Server)
{
if (server.Group == oldGroup)
{
server.Group = newGroup;
}
}
foreach (var server in Global.Settings.Server.Where(server => server.Group == oldGroup))
server.Group = newGroup;
}
/// <summary>
/// 订阅列表选中节点
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SubscribeLinkListView_SelectedIndexChanged(object sender, EventArgs e)
private void InitSubscribeLink()
{
var editingCanOverwrite = true;
if (_editingIndex != -1)
{
var targetItem = SubscribeLinkListView.Items[_editingIndex].SubItems;
editingCanOverwrite = RemarkTextBox.Text == targetItem[0].Text &&
LinkTextBox.Text == targetItem[1].Text &&
UserAgentTextBox.Text == targetItem[2].Text;
}
SubscribeLinkListView.Items.Clear();
if (SubscribeLinkListView.SelectedItems.Count == 1)
{
if (editingCanOverwrite)
foreach (var item in Global.Settings.SubscribeLink)
SubscribeLinkListView.Items.Add(new ListViewItem(new[]
{
SelectEditing(SubscribeLinkListView.SelectedItems[0].Index);
}
}
else if (SubscribeLinkListView.SelectedItems.Count > 1)
{
}
else if (editingCanOverwrite)
{
// 不选
// 重置
ResetEditingGroup();
}
}
private void SubscribeLinkListView_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
if (SubscribeLinkListView.SelectedItems.Count > 0)
"",
item.Remark,
item.Link,
!string.IsNullOrEmpty(item.UserAgent) ? item.UserAgent : WebUtil.DefaultUserAgent
})
{
pContextMenuStrip.Show(SubscribeLinkListView, e.Location);
}
}
}
Checked = item.Enable
});
private void SelectEditing(int index)
{
_editingIndex = index;
ListViewItem target;
target = SubscribeLinkListView.Items[index];
AddSubscriptionBox.Text = target.SubItems[0].Text;
RemarkTextBox.Text = target.SubItems[0].Text;
LinkTextBox.Text = target.SubItems[1].Text;
UserAgentTextBox.Text = target.SubItems[2].Text;
ResetEditingGroup();
}
private void ResetEditingGroup()
{
_editingIndex = -1;
AddSubscriptionBox.Text = string.Empty;
RemarkTextBox.Text = string.Empty;
LinkTextBox.Text = string.Empty;
UserAgentTextBox.Text = WebUtil.DefaultUserAgent;
}
private void ClearButton_Click(object sender, EventArgs e)
private void SetEditingGroup(int index)
{
ResetEditingGroup();
if (index == -1)
{
ResetEditingGroup();
AddButton.Text = i18N.Translate("Add");
return;
}
var item = Global.Settings.SubscribeLink[index];
AddSubscriptionBox.Text = item.Remark;
RemarkTextBox.Text = item.Remark;
LinkTextBox.Text = item.Link;
UserAgentTextBox.Text = item.UserAgent;
AddButton.Text = i18N.Translate("Modify");
}
#endregion
}
}

20
Netch/Models/Range.cs Normal file
View File

@@ -0,0 +1,20 @@
namespace Netch.Models
{
public readonly struct Range
{
public int Start { get; }
public int End { get; }
public Range(int start, int end)
{
Start = start;
End = end;
}
public bool InRange(int num)
{
return Start <= num && num <= End;
}
}
}

View File

@@ -1,31 +1,23 @@
using System;
using System.Threading.Tasks;
using Netch.Utils;
using Newtonsoft.Json;
namespace Netch.Models
{
public class Server:ICloneable
public class Server : ICloneable
{
/// <summary>
/// 备注
/// 延迟
/// </summary>
public string Remark;
[JsonIgnore]
public int Delay = -1;
/// <summary>
/// 组
/// </summary>
public string Group = "None";
/// <summary>
/// 代理类型
/// </summary>
public string Type;
/// <summary>
/// 倍率
/// </summary>
public double Rate = 1.0;
/// <summary>
/// 地址
/// </summary>
@@ -37,12 +29,26 @@ namespace Netch.Models
public ushort Port;
/// <summary>
/// 延迟
/// 倍率
/// </summary>
public int Delay = -1;
public double Rate = 1.0;
/// <summary>
/// 备注
/// </summary>
public string Remark;
/// <summary>
/// 获取备注
/// 代理类型
/// </summary>
public string Type;
public object Clone()
{
return MemberwiseClone();
}
/// <summary>
/// 获取备注
/// </summary>
/// <returns>备注</returns>
public override string ToString()
@@ -55,13 +61,8 @@ namespace Netch.Models
return $"[{ServerHelper.GetUtilByTypeName(Type)?.ShortName ?? "WTF"}][{Group}] {remark}";
}
public object Clone()
{
return MemberwiseClone();
}
/// <summary>
/// 测试延迟
/// 测试延迟
/// </summary>
/// <returns>延迟</returns>
public int Test()
@@ -70,25 +71,21 @@ namespace Netch.Models
{
var destination = DNS.Lookup(Hostname);
if (destination == null)
{
return Delay = -2;
}
var list = new Task<int>[3];
for (var i = 0; i < 3; i++)
{
list[i] = Task.Run(async () =>
{
try
{
return await Utils.Utils.TCPingAsync(destination, Port);
return Global.Settings.ServerTCPing ? await Utils.Utils.TCPingAsync(destination, Port) : Utils.Utils.ICMPing(destination, Port);
}
catch (Exception)
{
return -4;
}
});
}
Task.WaitAll(list[0], list[1], list[2]);

View File

@@ -1,83 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
namespace Netch.Models
{
/// <summary>
/// TUN/TAP 适配器配置类
/// TUN/TAP 适配器配置类
/// </summary>
public class TUNTAPConfig
{
/// <summary>
/// 地址
/// 地址
/// </summary>
public string Address = "10.0.236.10";
/// <summary>
/// 掩码
/// DNS
/// </summary>
public string Netmask = "255.255.255.0";
public List<string> DNS = new();
/// <summary>
/// 网关
/// 网关
/// </summary>
public string Gateway = "10.0.236.1";
/// <summary>
/// DNS
/// 掩码
/// </summary>
public List<string> DNS = new List<string>();
public string Netmask = "255.255.255.0";
/// <summary>
/// 使用自定义 DNS 设置
/// </summary>
public bool UseCustomDNS = false;
/// <summary>
/// 模式 2 下是否代理 DNS
/// 模式 2 下是否代理 DNS
/// </summary>
public bool ProxyDNS = false;
/// <summary>
/// 使用Fake DNS
/// 使用自定义 DNS 设置
/// </summary>
public bool UseCustomDNS = false;
/// <summary>
/// 使用Fake DNS
/// </summary>
public bool UseFakeDNS = false;
}
public class KcpConfig
{
public bool congestion = false;
public int downlinkCapacity = 100;
public int mtu = 1350;
public int readBufferSize = 2;
public int tti = 50;
public int uplinkCapacity = 12;
public int downlinkCapacity = 100;
public bool congestion = false;
public int readBufferSize = 2;
public int writeBufferSize = 2;
}
public class V2rayConfig
{
public bool XrayCone = false;
public bool AllowInsecure = true;
public KcpConfig KcpConfig = new KcpConfig();
public KcpConfig KcpConfig = new();
public bool UseMux = true;
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";
public string RulePath = "bin\\china_site_list";
}
/// <summary>
@@ -86,29 +86,61 @@ namespace Netch.Models
public class Setting
{
/// <summary>
/// 服务器选择位置
/// 服务器列表
/// </summary>
public int ServerComboBoxSelectedIndex = 0;
public readonly List<Server> Server = new();
/// <summary>
/// 模式选择位置
/// ACL规则
/// </summary>
public int ModeComboBoxSelectedIndex = 0;
public string ACL = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
public AioDNSConfig AioDNS = new();
/// <summary>
/// 是否关闭窗口时退出
/// 是否使用DLL启动Shadowsocks
/// </summary>
public bool BootShadowsocksFromDLL = true;
/// <summary>
/// 全局绕过 IP 列表
/// </summary>
public List<string> BypassIPs = new();
/// <summary>
/// 是否检查 Beta 更新
/// </summary>
public bool CheckBetaUpdate = false;
/// <summary>
/// 是否打开软件时检查更新
/// </summary>
public bool CheckUpdateWhenOpened = true;
/// <summary>
/// 测试所有服务器心跳/秒
/// </summary>
public int DetectionTick = 10;
/// <summary>
/// 是否关闭窗口时退出
/// </summary>
public bool ExitWhenClosed = false;
/// <summary>
/// 是否退出时停止
/// HTTP 本地端口
/// </summary>
public bool StopWhenExited = false;
public ushort HTTPLocalPort = 2802;
/// <summary>
/// 是否打开软件时启动加速
/// 语言设置
/// </summary>
public bool StartWhenOpened = false;
public string Language = "System";
/// <summary>
/// HTTP 和 Socks5 本地代理地址
/// </summary>
public string LocalAddress = "127.0.0.1";
/// <summary>
/// 是否启动后自动最小化
@@ -116,29 +148,9 @@ namespace Netch.Models
public bool MinimizeWhenStarted = false;
/// <summary>
/// 是否开机启动软件
/// 模式选择位置
/// </summary>
public bool RunAtStartup = false;
/// <summary>
/// 是否打开软件时检查更新
/// </summary>
public bool CheckUpdateWhenOpened = true;
/// <summary>
/// 是否检查 Beta 更新
/// </summary>
public bool CheckBetaUpdate = false;
/// <summary>
/// 是否打开软件时更新订阅
/// </summary>
public bool UpdateSubscribeatWhenOpened = false;
/// <summary>
/// 修改系统 DNS
/// </summary>
public bool ModifySystemDNS = false;
public int ModeComboBoxSelectedIndex = 0;
/// <summary>
/// 要修改为的系统 DNS
@@ -146,9 +158,54 @@ namespace Netch.Models
public string ModifiedDNS = "1.1.1.1,8.8.8.8";
/// <summary>
/// 解析服务器主机名
/// 修改系统 DNS
/// </summary>
public bool ResolveServerHostname = false;
public bool ModifySystemDNS = false;
/// <summary>
/// GFWList
/// </summary>
public string PAC = "https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac";
/// <summary>
/// PAC端口
/// </summary>
public int Pac_Port = 2803;
/// <summary>
/// PAC URL
/// </summary>
public string Pac_Url = "";
/// <summary>
/// 不代理TCP
/// </summary>
public bool ProcessNoProxyForTcp = false;
/// <summary>
/// 不代理UDP
/// </summary>
public bool ProcessNoProxyForUdp = false;
/// <summary>
/// 快捷配置数量
/// </summary>
public int ProfileCount = 4;
/// <summary>
/// 已保存的快捷配置
/// </summary>
public List<Profile> Profiles = new();
/// <summary>
/// 是否使用RDR内置SS
/// </summary>
public bool RedirectorSS = false;
/// <summary>
/// Redirector TCP 占用端口
/// </summary>
public ushort RedirectorTCPPort = 3901;
/// <summary>
/// 网页请求超时 毫秒
@@ -156,64 +213,44 @@ namespace Netch.Models
public int RequestTimeout = 10000;
/// <summary>
/// HTTP 本地端口
/// 解析服务器主机名
/// </summary>
public ushort HTTPLocalPort = 2802;
public bool ResolveServerHostname = false;
/// <summary>
/// Socks5 本地端口
/// 是否开机启动软件
/// </summary>
public bool RunAtStartup = false;
/// <summary>
/// 服务器选择位置
/// </summary>
public int ServerComboBoxSelectedIndex = 0;
/// <summary>
/// 服务器测试方式 false.ICMPing true.TCPing
/// </summary>
public bool ServerTCPing = true;
/// <summary>
/// Socks5 本地端口
/// </summary>
public ushort Socks5LocalPort = 2801;
/// <summary>
/// Redirector TCP 占用端口
/// 启动后延迟测试间隔/秒
/// </summary>
public ushort RedirectorTCPPort = 3901;
public int StartedPingInterval = -1;
/// <summary>
/// UDP Socket 占用端口
/// 是否打开软件时启动加速
/// </summary>
public ushort UDPSocketPort = 18291;
public bool StartWhenOpened = false;
/// <summary>
/// HTTP 和 Socks5 本地代理地址
/// 是否退出时停止
/// </summary>
public string LocalAddress = "127.0.0.1";
/// <summary>
/// TUNTAP 适配器配置
/// </summary>
public TUNTAPConfig TUNTAP = new TUNTAPConfig();
/// <summary>
/// 使用代理更新订阅
/// </summary>
public bool UseProxyToUpdateSubscription = false;
/// <summary>
/// 订阅链接列表
/// </summary>
public List<SubscribeLink> SubscribeLink = new List<SubscribeLink>();
/// <summary>
/// 服务器列表
/// </summary>
public readonly List<Server> Server = new List<Server>();
/// <summary>
/// 全局绕过 IP 列表
/// </summary>
public List<string> BypassIPs = new List<string>();
/// <summary>
/// 已保存的快捷配置
/// </summary>
public List<Profile> Profiles = new List<Profile>();
/// <summary>
/// 快捷配置数量
/// </summary>
public int ProfileCount = 4;
public bool StopWhenExited = false;
/// <summary>
/// STUN测试服务器
@@ -226,36 +263,34 @@ namespace Netch.Models
public int STUN_Server_Port = 3478;
/// <summary>
/// 是否启用启动后延迟测试
/// 订阅链接列表
/// </summary>
public bool StartedTcping = false;
public List<SubscribeLink> SubscribeLink = new();
/// <summary>
/// 启动后延迟测试间隔/秒
/// TUNTAP 适配器配置
/// </summary>
public int StartedTcping_Interval = 3;
public TUNTAPConfig TUNTAP = new();
/// <summary>
/// ACL规则
/// UDP Socket 占用端口
/// </summary>
public string ACL = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
public ushort UDPSocketPort = 18291;
/// <summary>
/// 是否使用DLL启动Shadowsocks
/// 是否打开软件时更新订阅
/// </summary>
public bool BootShadowsocksFromDLL = true;
public bool UpdateServersWhenOpened = false;
/// <summary>
/// 语言设置
/// 使用代理更新订阅
/// </summary>
public string Language = "System";
public bool UseProxyToUpdateSubscription = false;
public V2rayConfig V2RayConfig = new V2rayConfig();
public AioDNSConfig AioDNS = new AioDNSConfig();
public bool RedirectorSS = false;
public bool ProcessNoProxyForUdp = false;
public V2rayConfig V2RayConfig = new();
public Setting Clone()
{
return (Setting) MemberwiseClone();
}
}
}

View File

@@ -2,6 +2,11 @@
{
public class SubscribeLink
{
/// <summary>
/// 启用状态
/// </summary>
public bool Enable = true;
/// <summary>
/// 备注
/// </summary>
@@ -17,4 +22,4 @@
/// </summary>
public string UserAgent;
}
}
}

View File

@@ -13,7 +13,7 @@ namespace Netch
/// <param name="index">适配器索引</param>
/// <param name="metric">跃点数</param>
/// <returns>是否成功</returns>
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateRoute")]
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateRoute")]
public static extern bool CreateRoute(string address, int cidr, string gateway, int index, int metric = 0);
/// <summary>
@@ -25,33 +25,9 @@ namespace Netch
/// <param name="index">适配器索引</param>
/// <param name="metric">跃点数</param>
/// <returns>是否成功</returns>
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
public static extern bool DeleteRoute(string address, int cidr, string gateway, int index, int metric = 0);
/// <summary>
/// 设置直连
/// </summary>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetDIRECT();
/// <summary>
/// 设置全局
/// </summary>
/// <param name="remote">地址</param>
/// <param name="bypass">绕过</param>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetGlobal([MarshalAs(UnmanagedType.LPTStr)] string remote, [MarshalAs(UnmanagedType.LPTStr)] string bypass);
/// <summary>
/// 设置自动代理
/// </summary>
/// <param name="remote">URL</param>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetURL([MarshalAs(UnmanagedType.LPTStr)] string remote);
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();

View File

@@ -13,18 +13,14 @@ namespace Netch
public static class Netch
{
/// <summary>
/// 应用程序的主入口点
/// 应用程序的主入口点
/// </summary>
[STAThread]
public static void Main(string[] args)
{
if (args.Contains("-console"))
{
if (!NativeMethods.AttachConsole(-1))
{
NativeMethods.AllocConsole();
}
}
// 创建互斥体防止多次运行
using (var mutex = new Mutex(false, "Global\\Netch"))
@@ -36,12 +32,8 @@ namespace Netch
// 预创建目录
var directories = new[] {"mode", "data", "i18n", "logging"};
foreach (var item in directories)
{
if (!Directory.Exists(item))
{
Directory.CreateDirectory(item);
}
}
// 加载配置
Configuration.Load();
@@ -49,6 +41,12 @@ namespace Netch
// 加载语言
i18N.Load(Global.Settings.Language);
if (!Directory.Exists("bin") || !Directory.EnumerateFileSystemEntries("bin").Any())
{
MessageBoxX.Show(i18N.Translate("Please extract all files then run the program!"));
Environment.Exit(2);
}
// 检查是否已经运行
if (!mutex.WaitOne(0, false))
{
@@ -65,21 +63,14 @@ namespace Netch
var directory = new DirectoryInfo("logging");
foreach (var file in directory.GetFiles())
{
file.Delete();
}
foreach (var dir in directory.GetDirectories())
{
dir.Delete(true);
}
}
Logging.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
Task.Run(() =>
{
Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Application.ExecutablePath)}");
});
Task.Run(() => { Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Application.ExecutablePath)}"); });
Task.Run(() =>
{
Logging.Info("启动单实例");

View File

@@ -37,23 +37,6 @@
</ItemGroup>
<ItemGroup>
<COMReference Include="TaskScheduler.dll">
<Guid>e34cb9f1-c7f7-424c-be29-027dcc09363a</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<WrapperTool>tlbimp</WrapperTool>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>false</EmbedInteropTypes>
</COMReference>
<COMReference Include="NetFwTypeLib.dll">
<Guid>58fbcf7c-e7a9-467c-80b3-fc65e8fcca08</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>false</Isolated>
</COMReference>
<COMReference Include="NETCONLib.dll">
<Guid>{43E734CA-043D-4A70-9A2C-A8F254063D91}</Guid>
<VersionMajor>1</VersionMajor>
@@ -66,13 +49,17 @@
<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.62" />
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.65" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0"/>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
<PackageReference Include="TaskScheduler" Version="2.9.1" />
<PackageReference Include="WindowsAPICodePack-Shell" Version="1.1.1" />
<PackageReference Include="WindowsJobAPI" Version="5.0.0" />
<PackageReference Include="WindowsFirewallHelper" Version="2.0.4.70-beta2" />
<PackageReference Include="WindowsJobAPI" Version="5.0.1" />
<PackageReference Include="WindowsProxy" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,13 +1,15 @@
if %Configuration%==Release (
:: Merge dlls
%ILMergeConsolePath% /wildcards /out:%TargetDir%NetchMerged.exe ^
%ILMergeConsolePath% /wildcards /out:%TargetDir%Netch.exe ^
/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" ^
/targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8" ^
%TargetDir%Netch.exe ^
%TargetDir%*.dll
DEL /f %TargetDir%*.dll >NUL 2>&1
MOVE /Y %TargetDir%NetchMerged.exe %TargetDir%Netch.exe >NUL
DEL /f %TargetDir%*.config >NUL 2>&1
DEL /f %TargetDir%*.pdb >NUL 2>&1
)
RD /S /Q %TargetDir%bin >NUL 2>&1
@@ -18,6 +20,7 @@ XCOPY /s /Y %SolutionDir%binaries %TargetDir%bin\ >NUL
XCOPY /s /Y %SolutionDir%translations\i18n %TargetDir%i18n\ >NUL
XCOPY /s /Y %SolutionDir%modes\mode %TargetDir%mode\ >NUL
DEL /f %TargetDir%*.config >NUL 2>&1
DEL /f %TargetDir%*.pdb >NUL 2>&1
RD /s /Q %TargetDir%x86 >NUL 2>&1
RD /s /Q %TargetDir%de %TargetDir%es %TargetDir%fr %TargetDir%it %TargetDir%pl %TargetDir%ru %TargetDir%zh-CN >NUL 2>&1
exit 0

View File

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

View File

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

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

Binary file not shown.

View File

@@ -6,6 +6,7 @@
"If this is your first time using this software,\n please check https://netch.org to install supports first,\n or the program may report errors.": "如果你是第一次使用本软件,\n请务必前往 https://netch.org 安装程序所需依赖,\n否则程序将无法正常运行",
"Netch is already running": "Netch 已经在运行中",
"Missing File or runtime components": "缺少文件或运行库",
"Please extract all files then run the program!": "请先解压所有文件再执行程序!",
"Start": "启动",
"Stop": "停止",
@@ -28,7 +29,7 @@
"Import Servers From Clipboard": "从剪贴板导入服务器",
"Import servers error!": "未找到可导入的链接!",
"Add [{0}] Server": "添加 [{0}] 服务器",
"Netch is now minimized to the notification bar, double click this icon to restore.": "Netch 已最小化至通知栏,双击此图标恢复窗口",
"Netch is now minimized to the notification bar, double click this icon to restore.": "Netch 已最小化至通知栏,双击此图标恢复窗口",
"New version available": "发现新版本",
"Already latest version": "已经是最新版本",
"New version found failed": "寻找新版本失败",
@@ -66,10 +67,18 @@
"Subscribe": "订阅",
"Manage Subscribe Links": "管理订阅链接",
"Update Servers From Subscribe Links": "从订阅链接更新服务器",
"Update Servers From Subscribe Links With Proxy": "使用代理从订阅链接更新服务器",
"No subscription link": "没有任何一条订阅链接",
"Updating in the background": "正在后台更新中",
"Updating {0}": "正在更新 {0}",
"Update {1} server(s) from {0}": "从 {0} 更新 {1} 个服务器",
"Update servers error from {0}": "从 {0} 更新服务器失败",
"Delete the corresponding group of items in the server list?": "是否删除订阅对应服务器?",
"Confirm deletion?": "确认删除?",
"DeleteServer": "删除订阅节点",
"Status": "状态",
"Remark": "备注",
"Link": "链接",
"Unselect": "取消选择",
"Options": "选项",
"NF Service": "NF 服务",
@@ -81,10 +90,17 @@
"Modes have been reload": "模式已重载",
"Clean DNS Cache": "清理 DNS 缓存",
"DNS cache cleanup succeeded": "DNS 缓存清理成功",
"Remove Netch Firewall Rules": "移除 Netch 防火墙规则",
"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": "关于",
@@ -113,9 +129,10 @@
"Add": "添加",
"Scan": "扫描",
"Save": "保存",
"Add / Modify": "保存/修改",
"Modify": "修改",
"Select a folder": "选择一个目录",
"Please enter an process name (xxx.exe)": "请输入一个进程名xxx.exe",
"Rule does not conform to C++ regular expression syntax": "规则不符合 C++ 正则表达式语法",
"Scan completed": "扫描完成",
"Mode added successfully": "模式添加成功",
"Mode updated successfully": "模式修改成功",
@@ -149,21 +166,23 @@
"Exit when closed": "关闭时退出",
"Stop when exited": "退出时停止",
"Global Bypass IPs": "全局直连 IP",
"Port value illegal. Try again.": "端口值非法。请重试",
"Port value illegal. Try again.": "端口值非法。请重试",
"Check update when opened": "打开软件时检查更新",
"Check Beta update": "检查 Beta 更新",
"Update subscribeat when opened": "自动更新订阅",
"Update Servers when opened": "打开软件时更新服务器",
"SS DLL": "SS DLL",
"Modify System DNS": "修改系统 DNS",
"No Proxy for Udp": "不代理Udp流量",
"No Proxy for Udp": "不代理 UDP 流量",
"No Proxy for Tcp": "不代理 TCP 流量",
"ProfileCount": "快捷配置数量",
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试",
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试",
"Detection interval value illegal. Try again.": "检测间隔值非法。请重试",
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试",
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试",
"Detection interval value illegal. Try again.": "检测间隔值非法。请重试",
"TUN/TAP driver is not detected. Is it installed now?": "未检测到 TUN/TAP 驱动,是否现在安装?",
"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 服务器端口",
@@ -171,6 +190,7 @@
"Language": "语言",
"Tap Network Sharing": "Tap 网络共享",
"Resolve Server Hostname": "解析服务器主机名",
"FullCone Support (Required Server Xray-core v1.3.0+)": "FullCone 支持(需服务端 Xray-core v1.3.0+",
"Profile": "配置名",
"Profiles": "配置",
@@ -181,6 +201,7 @@
"Unable to start? Click me to download": "无法启动?点我下载依赖",
"The {0} port is in use.": "{0} 端口已被占用",
"The {0} port is reserved by system.": "{0} 端口是系统保留端口",
"[Web Proxy] Bypass LAN": "[网页代理] 绕过局域网",
"[Non Web Proxy] Bypass LAN": "[不设置代理] 绕过局域网",
@@ -188,4 +209,4 @@
"[Web Proxy] Bypass LAN and China": "[网页代理] 绕过局域网和中国大陆",
"[Non Web Proxy] Bypass LAN and China": "[不设置代理] 绕过局域网和中国大陆",
"[TUN/TAP] Bypass LAN and China": "[TUN/TAP] 绕过局域网和中国大陆"
}
}

View File

@@ -8,7 +8,7 @@ namespace Netch.Servers.Shadowsocks
{
public class SSController : Guard, IServerController
{
public override string Name { get; protected set; } = "Shadowsocks";
public override string Name { get; } = "Shadowsocks";
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
public ushort? Socks5LocalPort { get; set; }

View File

@@ -1,7 +1,6 @@
using System.Text;
using Netch.Controllers;
using Netch.Models;
using Netch.Utils;
namespace Netch.Servers.ShadowsocksR
{
@@ -9,7 +8,7 @@ namespace Netch.Servers.ShadowsocksR
{
public override string MainFile { get; protected set; } = "ShadowsocksR.exe";
public override string Name { get; protected set; } = "ShadowsocksR";
public override string Name { get; } = "ShadowsocksR";
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }

View File

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

View File

@@ -3,7 +3,6 @@ using System.IO;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Trojan.Models;
using Netch.Utils;
using Newtonsoft.Json;
namespace Netch.Servers.Trojan
@@ -17,15 +16,14 @@ namespace Netch.Servers.Trojan
}
public override string MainFile { get; protected set; } = "Trojan.exe";
public override string Name { get; protected set; } = "Trojan";
public override string Name { get; } = "Trojan";
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s, in Mode mode)
{
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(),
@@ -35,8 +33,15 @@ namespace Netch.Servers.Trojan
{
server.Password
}
}));
};
if (!string.IsNullOrWhiteSpace(server.Host))
trojanConfig.ssl.sni = server.Host;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(trojanConfig, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
return StartInstanceAuto("-c ..\\data\\last.json");
}

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace Netch.Servers.VMess.Models
namespace Netch.Servers.V2ray.Models
{
public class V2rayConfig
{
@@ -40,7 +40,6 @@ namespace Netch.Servers.VMess.Models
public List<UsersItem> clients { get; set; }
public string decryption { get; set; }
}
@@ -125,7 +124,6 @@ namespace Netch.Servers.VMess.Models
public int level { get; set; }
}
public class Mux
{
public bool enabled { get; set; }
@@ -218,7 +216,6 @@ namespace Netch.Servers.VMess.Models
public TCPRequestHeaders headers;
}
public class TCPRequestHeaders
{
public string Host;

View File

@@ -1,4 +1,4 @@
namespace Netch.Servers.VMess.Models
namespace Netch.Servers.V2ray.Models
{
/// <summary>
/// 使用 v2rayN 定义的 VMess 链接格式

View File

@@ -1,11 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using Netch.Models;
using Netch.Servers.VMess.Models;
using Netch.Servers.V2ray.Models;
using Newtonsoft.Json;
using V2rayConfig = Netch.Servers.VMess.Models.V2rayConfig;
using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig;
namespace Netch.Servers.VMess.Utils
namespace Netch.Servers.V2ray.Utils
{
public static class V2rayConfigUtils
{
@@ -214,7 +214,7 @@ namespace Netch.Servers.VMess.Utils
outbound.settings.servers = null;
break;
}
case VMess vmess:
case VMess.VMess vmess:
{
var vnextItem = new VnextItem
{
@@ -261,7 +261,7 @@ namespace Netch.Servers.VMess.Utils
}
}
private static void boundStreamSettings(VMess server, ref StreamSettings streamSettings)
private static void boundStreamSettings(VMess.VMess server, ref StreamSettings streamSettings)
{
try
{

View File

@@ -1,25 +1,23 @@
using System.IO;
using System.IO;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.VMess.Utils;
using Netch.Servers.V2ray.Utils;
namespace Netch.Servers.VMess
namespace Netch.Servers.V2ray
{
public class VMessController : Guard, IServerController
public class V2RayController : Guard, IServerController
{
public VMessController()
public V2RayController()
{
StartedKeywords.Add("started");
StoppedKeywords.AddRange(new[] {"config file not readable", "failed to"});
}
public override string MainFile { get; protected set; } = "xray.exe";
public override string Name { get; protected set; } = "VMess";
public override string MainFile { get; protected set; } = "v2ray.exe";
public override string Name { get; } = "Xray";
public ushort? Socks5LocalPort { get; set; }
public string LocalAddress { get; set; }
public bool Start(in Server s,in Mode mode)
public virtual bool Start(in Server s, in Mode mode)
{
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
return StartInstanceAuto("-config ..\\data\\last.json");
@@ -29,5 +27,12 @@ namespace Netch.Servers.VMess
{
StopInstance();
}
protected override void InitInstance(string argument)
{
base.InitInstance(argument);
if (!Global.Settings.V2RayConfig.XrayCone)
Instance.StartInfo.Environment["XRAY_CONE_DISABLED"] = "true";
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Netch.Models;
using Netch.Servers.VMess;
namespace Netch.Servers.VLESS

View File

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

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.V2ray;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.VLESS
@@ -36,7 +37,7 @@ namespace Netch.Servers.VLESS
public IServerController GetController()
{
return new VLESSController();
return new V2RayController();
}
public IEnumerable<Server> ParseUri(string text)

View File

@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using Netch.Models;
@@ -70,7 +69,7 @@ namespace Netch.Servers.VMess
/// <summary>
/// Mux 多路复用
/// </summary>
public bool? UseMux { get; set; } = true;
public bool? UseMux { get; set; } = false;
}
public class VMessGlobal

View File

@@ -2,8 +2,9 @@ using System;
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.V2ray;
using Netch.Servers.V2ray.Models;
using Netch.Servers.VMess.Form;
using Netch.Servers.VMess.Models;
using Netch.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -56,7 +57,7 @@ namespace Netch.Servers.VMess
public IServerController GetController()
{
return new VMessController();
return new V2RayController();
}
public IEnumerable<Server> ParseUri(string text)

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
@@ -8,7 +7,6 @@ using Microsoft.Diagnostics.Tracing.Session;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Socks5;
namespace Netch.Utils
{
@@ -54,7 +52,7 @@ namespace Netch.Utils
/// <summary>
/// 根据程序名统计流量
/// </summary>
public static void NetTraffic(in Server server, in Mode mode)
public static void NetTraffic()
{
if (!Global.Flags.IsWindows10Upper)
return;
@@ -100,6 +98,13 @@ namespace Netch.Utils
Logging.Info("流量统计进程:" + string.Join(",",
instances.Select(instance => $"({instance.Id})" + instance.ProcessName).ToArray()));
received = 0;
if (!instances.Any())
return;
Global.MainForm.BandwidthState(true);
Task.Run(() =>
{
tSession = new TraceEventSession("KernelAndClrEventsSession");

View File

@@ -1,12 +1,13 @@
using System;
using System.IO;
using System.Linq;
using NetFwTypeLib;
using WindowsFirewallHelper;
namespace Netch.Utils
{
public static class Firewall
{
private const string Netch = "Netch";
private static readonly string[] ProgramPath =
{
"bin/NTT.exe",
@@ -15,53 +16,30 @@ namespace Netch.Utils
"bin/ShadowsocksR.exe",
"bin/Trojan.exe",
"bin/tun2socks.exe",
"bin/v2ray.exe",
"bin/xray.exe",
"Netch.exe"
};
private const string Netch = "Netch";
private const string NetchAutoRule = "NetchAutoRule";
/// <summary>
/// 添加防火墙规则 (非 Netch 自带程序)
/// </summary>
/// <param name="exeFullPath"></param>
public static void AddFwRule(string exeFullPath)
{
AddFwRule(NetchAutoRule, exeFullPath);
}
/// <summary>
/// 清除防火墙规则 (非 Netch 自带程序)
/// </summary>
public static void RemoveFwRules()
{
try
{
RemoveFwRules(NetchAutoRule);
}
catch (Exception e)
{
Logging.Warning("添加防火墙规则错误\n" + e);
}
}
/// <summary>
/// Netch 自带程序添加防火墙
/// Netch 自带程序添加防火墙
/// </summary>
public static void AddNetchFwRules()
{
try
{
if (GetFwRulePath(Netch).StartsWith(Global.NetchDir) && GetFwRulesNumber(Netch) >= ProgramPath.Length) return;
RemoveNetchFwRules();
var rule = FirewallManager.Instance.Rules.FirstOrDefault(r => r.Name == Netch);
if (rule != null)
{
if (rule.Name.StartsWith(Global.NetchDir))
return;
RemoveNetchFwRules();
}
foreach (var p in ProgramPath)
{
var path = Path.GetFullPath(p);
if (File.Exists(path))
{
AddFwRule("Netch", path);
}
AddFwRule(Netch, path);
}
}
catch (Exception e)
@@ -71,72 +49,29 @@ namespace Netch.Utils
}
/// <summary>
/// 清除防火墙规则 (Netch 自带程序)
/// 清除防火墙规则 (Netch 自带程序)
/// </summary>
private static void RemoveNetchFwRules()
public static void RemoveNetchFwRules()
{
try
{
RemoveFwRules(Netch);
foreach (var rule in FirewallManager.Instance.Rules.Where(r => r.Name == Netch))
FirewallManager.Instance.Rules.Remove(rule);
}
catch (Exception e)
{
Logging.Warning("清除防火墙规则错误\n" + e);
// ignored
}
}
#region
private static readonly INetFwPolicy2 FwPolicy = (INetFwPolicy2) Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
private static void AddFwRule(string ruleName, string exeFullPath)
{
var rule = NewFwRule();
var rule = FirewallManager.Instance.CreateApplicationRule(ruleName, FirewallAction.Allow, exeFullPath);
rule.Direction = FirewallDirection.Inbound;
rule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
// ApplicationName 大小不敏感
rule.ApplicationName = exeFullPath;
// rule.Description = "";
rule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
rule.Enabled = true;
rule.InterfaceTypes = "All";
rule.Name = ruleName;
FwPolicy.Rules.Add(rule);
}
private static void RemoveFwRules(string ruleName)
{
var c = GetFwRulesNumber(ruleName);
foreach (var _ in new bool[c])
{
FwPolicy.Rules.Remove(ruleName);
}
}
private static INetFwRule NewFwRule()
{
return (INetFwRule) Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
}
private static string GetFwRulePath(string ruleName)
{
try
{
var rule = (INetFwRule2) FwPolicy.Rules.Item(ruleName);
return rule.ApplicationName;
}
catch (Exception)
{
return "";
}
}
private static int GetFwRulesNumber(string ruleName)
{
return FwPolicy.Rules.Cast<INetFwRule2>().Count(rule => rule.Name == ruleName);
FirewallManager.Instance.Rules.Add(rule);
}
#endregion

View File

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

View File

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

View File

@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Management;
using Netch.Controllers;
using Netch.Models.WinFW;

View File

@@ -16,12 +16,21 @@ namespace Netch.Utils
public static readonly string ModeDirectory = Path.Combine(Global.NetchDir, $"{MODE_DIR}\\");
public static string GetRelativePath(string fullName) => fullName.Substring(ModeDirectory.Length);
public static string GetFullPath(string relativeName) => Path.Combine(ModeDirectory, relativeName);
public static string GetFullPath(Mode mode) => Path.Combine(ModeDirectory, mode.RelativePath);
public static string GetRelativePath(string fullName)
{
return fullName.Substring(ModeDirectory.Length);
}
public static string GetFullPath(string relativeName)
{
return Path.Combine(ModeDirectory, relativeName);
}
public static string GetFullPath(Mode mode)
{
return Path.Combine(ModeDirectory, mode.RelativePath);
}
/// <summary>
/// 从模式文件夹读取模式并为 <see cref="Forms.MainForm.ModeComboBox"/> 绑定数据
/// 从模式文件夹读取模式并为 <see cref="Forms.MainForm.ModeComboBox" /> 绑定数据
/// </summary>
public static void Load()
{
@@ -99,16 +108,12 @@ namespace Netch.Utils
public static void WriteFile(Mode mode)
{
if (!Directory.Exists(ModeDirectory))
{
Directory.CreateDirectory(ModeDirectory);
}
var fullName = GetFullPath(mode.RelativePath ?? mode.FileName + ".txt");
if (mode.RelativePath == null && File.Exists(fullName))
{
throw new Exception("新建模式的文件名已存在,请贡献者检查代码");
}
// 写入到模式文件里
File.WriteAllText(fullName, mode.ToFileString());
@@ -131,9 +136,7 @@ namespace Netch.Utils
{
var fullName = GetFullPath(mode);
if (File.Exists(fullName))
{
File.Delete(fullName);
}
Global.Modes.Remove(mode);
Global.MainForm.InitMode();
@@ -166,6 +169,7 @@ namespace Netch.Utils
modeController = new NFController();
port = Global.Settings.RedirectorTCPPort;
portName = "Redirector TCP";
portType = PortType.TCP;
break;
case 1:
case 2:
@@ -176,6 +180,7 @@ namespace Netch.Utils
modeController = new HTTPController();
port = Global.Settings.HTTPLocalPort;
portName = "HTTP";
portType = PortType.TCP;
MainForm.StatusPortInfoText.HttpPort = (ushort) port;
break;
case 4:

View File

@@ -24,11 +24,21 @@ namespace Netch.Utils
{
try
{
if (PortHelper.PortInUse(Global.Settings.UDPSocketPort))
{
Global.Settings.UDPSocketPort = PortHelper.GetAvailablePort();
Configuration.Save();
}
const int tryLimit = 3;
var i = tryLimit;
while (i > 0)
try
{
PortHelper.CheckPort(Global.Settings.UDPSocketPort, PortType.UDP);
if (i != tryLimit)
Configuration.Save();
break;
}
catch
{
Global.Settings.UDPSocketPort = PortHelper.GetAvailablePort(PortType.UDP);
i--;
}
var data = new byte[1024];
var newsock = new UdpClient(new IPEndPoint(IPAddress.Loopback, Global.Settings.UDPSocketPort));
@@ -38,9 +48,7 @@ namespace Netch.Utils
var result = await newsock.ReceiveAsync();
data = result.Buffer;
if (Enum.TryParse<Commands>(Encoding.ASCII.GetString(data, 0, data.Length), out var command))
{
OnCalled(command);
}
}
}
catch (Exception e)
@@ -53,14 +61,12 @@ namespace Netch.Utils
{
try
{
using (var udpClient = new UdpClient(Global.Settings.UDPSocketPort))
{
udpClient.Connect(IPAddress.Loopback, Global.Settings.UDPSocketPort);
var sendBytes = Encoding.ASCII.GetBytes(command.ToString());
await udpClient.SendAsync(sendBytes, sendBytes.Length);
using var udpClient = new UdpClient(Global.Settings.UDPSocketPort);
udpClient.Connect(IPAddress.Loopback, Global.Settings.UDPSocketPort);
var sendBytes = Encoding.ASCII.GetBytes(command.ToString());
await udpClient.SendAsync(sendBytes, sendBytes.Length);
udpClient.Close();
}
udpClient.Close();
}
catch (Exception e)
{

View File

@@ -3,20 +3,22 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using Netch.Models;
namespace Netch.Utils
{
public static class PortHelper
{
private static readonly List<ushort[]> TCPExcludedRanges = new List<ushort[]>();
private static readonly List<ushort[]> UDPExcludedRanges = new List<ushort[]>();
private static readonly List<Range> TCPReservedRanges = new();
private static readonly List<Range> UDPReservedRanges = new();
private static readonly IPGlobalProperties NetInfo = IPGlobalProperties.GetIPGlobalProperties();
static PortHelper()
{
try
{
GetExcludedPortRange(PortType.TCP, ref TCPExcludedRanges);
GetExcludedPortRange(PortType.UDP, ref UDPExcludedRanges);
GetReservedPortRange(PortType.TCP, ref TCPReservedRanges);
GetReservedPortRange(PortType.UDP, ref UDPReservedRanges);
}
catch (Exception e)
{
@@ -24,7 +26,7 @@ namespace Netch.Utils
}
}
private static void GetExcludedPortRange(PortType portType, ref List<ushort[]> targetList)
private static void GetReservedPortRange(PortType portType, ref List<Range> targetList)
{
var lines = new List<string>();
var process = new Process
@@ -48,47 +50,20 @@ namespace Netch.Utils
var splitLine = false;
foreach (var line in lines)
{
if (!splitLine)
{
if (line.StartsWith("-"))
{
splitLine = true;
}
}
else
{
if (line == string.Empty)
break;
var value = line.Trim().Split(' ').Where(s => s != string.Empty);
var value = line.Trim().Split(' ').Where(s => s != string.Empty).ToArray();
ushort port = 0;
var _ = (from s1 in value
where ushort.TryParse(s1, out port)
select port).ToArray();
targetList.Add(_);
targetList.Add(new Range(ushort.Parse(value[0]), ushort.Parse(value[1])));
}
}
}
/// <summary>
/// 检查端口是否是保留端口
/// </summary>
/// <param name="port">端口</param>
/// <param name="type">端口类型</param>
/// <returns>是否是保留端口</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
private static bool IsPortExcluded(ushort port, PortType type)
{
return type switch
{
PortType.TCP => TCPExcludedRanges.Any(range => range[0] <= port && port <= range[1]),
PortType.UDP => UDPExcludedRanges.Any(range => range[0] <= port && port <= range[1]),
PortType.Both => IsPortExcluded(port, PortType.TCP) || IsPortExcluded(port, PortType.UDP),
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
}
/// <summary>
@@ -97,39 +72,83 @@ namespace Netch.Utils
/// <param name="port">端口</param>
/// <param name="type">检查端口类型</param>
/// <returns>是否被占用</returns>
public static bool PortInUse(ushort port, PortType type = PortType.Both)
public static void CheckPort(ushort port, PortType type = PortType.Both)
{
var netInfo = IPGlobalProperties.GetIPGlobalProperties();
var isTcpUsed = type != PortType.UDP &&
(IsPortExcluded(port, PortType.TCP) ||
netInfo.GetActiveTcpListeners().Any(ipEndPoint => ipEndPoint.Port == port));
var isUdpUsed = type != PortType.TCP &&
(IsPortExcluded(port, PortType.UDP) ||
netInfo.GetActiveUdpListeners().Any(ipEndPoint => ipEndPoint.Port == port));
var isPortExcluded = !UsingPorts.Contains(port);
return isPortExcluded && (isTcpUsed || isUdpUsed);
switch (type)
{
case PortType.Both:
CheckPort(port, PortType.TCP);
CheckPort(port, PortType.UDP);
break;
default:
CheckPortInUse(port, type);
CheckPortReserved(port, type);
break;
}
}
private static void CheckPortInUse(ushort port, PortType type)
{
switch (type)
{
case PortType.Both:
CheckPortInUse(port, PortType.TCP);
CheckPortInUse(port, PortType.UDP);
break;
case PortType.TCP:
if (NetInfo.GetActiveTcpListeners().Any(ipEndPoint => ipEndPoint.Port == port))
throw new PortInUseException();
break;
case PortType.UDP:
if (NetInfo.GetActiveUdpListeners().Any(ipEndPoint => ipEndPoint.Port == port))
throw new PortInUseException();
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
}
/// <summary>
/// 检查端口是否是保留端口
/// </summary>
private static void CheckPortReserved(ushort port, PortType type)
{
switch (type)
{
case PortType.Both:
CheckPortReserved(port, PortType.TCP);
CheckPortReserved(port, PortType.UDP);
return;
case PortType.TCP:
if (TCPReservedRanges.Any(range => range.InRange(port)))
throw new PortReservedException();
break;
case PortType.UDP:
if (UDPReservedRanges.Any(range => range.InRange(port)))
throw new PortReservedException();
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
}
public static ushort GetAvailablePort()
public static ushort GetAvailablePort(PortType portType = PortType.Both)
{
var random = new Random();
for (ushort i = 0; i < 55535; i++)
{
var p = (ushort) random.Next(10000, 65535);
if (!PortInUse(p))
try
{
CheckPort(p, portType);
return p;
}
catch (Exception)
{
// ignored
}
}
throw new Exception("Cant Generate Available Port");
throw new Exception();
}
/// <summary>
/// 记录Netch使用的端口
/// </summary>
public static readonly List<ushort> UsingPorts = new List<ushort>();
}
/// <summary>
@@ -145,4 +164,7 @@ namespace Netch.Utils
public class PortInUseException : Exception
{
}
public class PortReservedException : Exception
{
}
}

View File

@@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Timers;
using Netch.Models;
using Newtonsoft.Json.Linq;
@@ -9,14 +11,87 @@ namespace Netch.Utils
{
public static class ServerHelper
{
public static readonly IEnumerable<IServerUtil> ServerUtils;
static ServerHelper()
{
var serversUtilsTypes = Assembly.GetExecutingAssembly().GetExportedTypes().Where(type => type.GetInterfaces().Any(t => t == typeof(IServerUtil)));
var serversUtilsTypes = Assembly.GetExecutingAssembly().GetExportedTypes().Where(type => type.GetInterfaces().Contains(typeof(IServerUtil)));
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil) Activator.CreateInstance(t)).OrderBy(util => util.Priority);
}
#region Delay
public static class DelayTestHelper
{
private static readonly Timer Timer;
private static bool _mux;
public static readonly Range Range = new(0, int.MaxValue / 1000);
static DelayTestHelper()
{
Timer = new Timer
{
Interval = 10000,
AutoReset = true
};
Timer.Elapsed += (_, _) => TestAllDelay();
}
public static bool Enabled
{
get => Timer.Enabled;
set
{
if (!ValueIsEnabled(Global.Settings.DetectionTick))
return;
Timer.Enabled = value;
}
}
public static int Interval => (int) (Timer.Interval / 1000);
private static bool ValueIsEnabled(int value)
{
return value != 0 && Range.InRange(value);
}
public static event EventHandler TestDelayFinished;
public static void TestAllDelay()
{
if (_mux)
return;
try
{
_mux = true;
Parallel.ForEach(Global.Settings.Server, new ParallelOptions {MaxDegreeOfParallelism = 16},
server => { server.Test(); });
_mux = false;
TestDelayFinished?.Invoke(null, new EventArgs());
}
catch (Exception)
{
// ignored
}
}
public static void UpdateInterval()
{
Timer.Stop();
if (!ValueIsEnabled(Global.Settings.DetectionTick))
return;
Timer.Interval = Global.Settings.DetectionTick * 1000;
Task.Run(TestAllDelay);
Timer.Start();
}
}
#endregion
#region Handler
public static readonly IEnumerable<IServerUtil> ServerUtils;
public static Server ParseJObject(JObject o)
{
var handle = GetUtilByTypeName((string) o["Type"]);
@@ -47,5 +122,7 @@ namespace Netch.Utils
{
return ServerUtils.FirstOrDefault(i => i.UriScheme.Any(s => s.Equals(typeName)));
}
#endregion
}
}

View File

@@ -5,7 +5,6 @@ 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;

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

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

View File

@@ -24,6 +24,10 @@ namespace Netch.Utils
{
try
{
if (!item.Enable)
{
return;
}
var request = WebUtil.CreateRequest(item.Link);
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;

View File

@@ -12,7 +12,8 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using MaxMind.GeoIP2;
using TaskScheduler;
using Microsoft.Win32.TaskScheduler;
using Task = System.Threading.Tasks.Task;
namespace Netch.Utils
{
@@ -56,12 +57,20 @@ namespace Netch.Utils
return timeout;
}
public static 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(":"))
{
Hostname = Hostname.Split(':')[0];
}
string Country;
try
@@ -77,13 +86,9 @@ namespace Netch.Utils
var DnsResult = DNS.Lookup(Hostname);
if (DnsResult != null)
{
Country = databaseReader.Country(DnsResult).Country.IsoCode;
}
else
{
Country = "Unknown";
}
}
}
catch (Exception)
@@ -126,7 +131,10 @@ namespace Netch.Utils
}
}
public static string GetFileVersion(string file) => File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
public static string GetFileVersion(string file)
{
return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
}
public static bool SearchOutboundAdapter(bool logging = true)
{
@@ -183,19 +191,12 @@ namespace Netch.Utils
{
e.DrawBackground();
if (e.Index >= 0)
{
var brush = new SolidBrush(cbx.ForeColor);
if (e.Index < 0)
return;
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
brush = SystemBrushes.HighlightText as SolidBrush;
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, new StringFormat
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center
});
}
TextRenderer.DrawText(e.Graphics, cbx.Items[e.Index].ToString(), cbx.Font, e.Bounds,
(e.State & DrawItemState.Selected) == DrawItemState.Selected ? SystemColors.HighlightText : cbx.ForeColor,
TextFormatFlags.HorizontalCenter);
}
}
@@ -204,34 +205,32 @@ namespace Netch.Utils
func.Invoke(component);
switch (component)
{
case ListView listView:
// ListView sub item
foreach (var item in listView.Columns.Cast<ColumnHeader>())
ComponentIterator(item, func);
break;
case ToolStripMenuItem toolStripMenuItem:
// Iterator Menu strip sub item
foreach (var item in toolStripMenuItem.DropDownItems.Cast<ToolStripItem>())
{
ComponentIterator(item, func);
}
break;
case MenuStrip menuStrip:
// Menu Strip
foreach (var item in menuStrip.Items.Cast<ToolStripItem>())
{
ComponentIterator(item, func);
}
break;
case ContextMenuStrip contextMenuStrip:
foreach (var item in contextMenuStrip.Items.Cast<ToolStripItem>())
{
ComponentIterator(item, func);
}
break;
case Control control:
foreach (var c in control.Controls.Cast<Control>())
{
ComponentIterator(c, func);
}
if (control.ContextMenuStrip != null)
ComponentIterator(control.ContextMenuStrip, func);
@@ -242,47 +241,35 @@ namespace Netch.Utils
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
}
const string TaskName = "Netch Startup";
var folder = TaskService.Instance.GetFolder("\\");
var taskIsExists = folder.Tasks.Any(task => task.Name == TaskName);
if (Global.Settings.RunAtStartup)
{
if (taskIsExists)
folder.DeleteTask("Netch Startup", 0);
folder.DeleteTask(TaskName, false);
var task = scheduler.NewTask(0);
task.RegistrationInfo.Author = "Netch";
task.RegistrationInfo.Description = "Netch run at startup.";
task.Principal.RunLevel = _TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
var td = TaskService.Instance.NewTask();
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;
td.RegistrationInfo.Author = "Netch";
td.RegistrationInfo.Description = "Netch run at startup.";
td.Principal.RunLevel = TaskRunLevel.Highest;
td.Triggers.Add(new LogonTrigger());
td.Actions.Add(new ExecAction(Application.ExecutablePath));
task.Settings.ExecutionTimeLimit = "PT0S";
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
td.Settings.DisallowStartIfOnBatteries = false;
td.Settings.RunOnlyIfIdle = false;
td.Settings.Compatibility = TaskCompatibility.V2_1;
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null,
_TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
TaskService.Instance.RootFolder.RegisterTaskDefinition("Netch Startup", td);
}
else
{
if (taskIsExists)
folder.DeleteTask("Netch Startup", 0);
folder.DeleteTask(TaskName, false);
}
}

View File

@@ -121,6 +121,9 @@ namespace Netch.Utils
case ToolStripItem c:
c.Text = Translate(c.Text);
break;
case ColumnHeader c:
c.Text = Translate(c.Text);
break;
}
});
}

View File

@@ -5,7 +5,6 @@
[![Version](https://img.shields.io/github/v/release/NetchX/Netch)](https://github.com/NetchX/Netch/releases)
[![Downloads](https://img.shields.io/github/downloads/NetchX/Netch/total.svg)](https://github.com/NetchX/Netch/releases)
[![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)](https://github.com/NetchX/Netch/actions)
[![Website](https://img.shields.io/website?url=https%3A%2F%2Fnetch.org)](https://netch.org/)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
[中文说明](/docs/README.zh-CN.md)
@@ -60,9 +59,10 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
- [go-tun2socks](https://github.com/eycorsican/go-tun2socks)
- [shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev)
- [shadowsocksr-libev](https://github.com/shadowsocksrr/shadowsocksr-libev)
- [v2ray-core](https://github.com/v2ray/v2ray-core)
- [v2ray-core](https://github.com/v2fly/v2ray-core)
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [PAC](https://github.com/HMBSbige/Text_Translation/blob/master/ShadowsocksR/ss_white.pac)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)

View File

@@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit" Version="3.13.1" />
</ItemGroup>
</Project>

View File

@@ -34,19 +34,21 @@
### 模式 1 进程代理模式
- 根据进程名进行代理
- 底层依赖于 [NetFilter SDK](https://netfiltersdk.com) 和 Redirector.exe未开源
- 底层依赖于 [NetFilter SDK](https://netfiltersdk.com)
- 对于第一次使用 Netch 的用户而言,不需要做多余的事情
- 若 [NetFilter SDK](https://netfiltersdk.com) 的驱动不存在,会自动安装
- 若驱动版本过低,会自动更新
范例文件
在这个模式里,第一行只有备注是有用的
在这个模式里,第一行只有备注是有用的规则内容支持C++正则表达式
```
# 备注
进程名 1会被代理
进程名 2
!进程名 2(不会被代理)
csgo.exe
\\steam\\代理运行路径包含steam的所有程序
...
```
@@ -131,7 +133,7 @@
## Socks 5 代理中转
说明一下Netch 并非是以网页代理为目的开发的程序,如果需要网络代理为目的的程序,需要 PAC规则分流订阅管理等功能的请参考使用以下软件而非 Netch均为 Windows 平台)
说明一下Netch 并非是以网页代理为目的开发的程序,如果需要网络代理为目的的程序,需要 PAC规则分流订阅管理等功能的尽量参考使用以下软件而非 Netch均为 Windows 平台)
ShadowsocksR

View File

@@ -5,7 +5,6 @@
[![版本](https://img.shields.io/github/v/release/NetchX/Netch)](https://github.com/NetchX/Netch/releases)
[![下载](https://img.shields.io/github/downloads/NetchX/Netch/total.svg)](https://github.com/NetchX/Netch/releases)
[![Netch CI](https://github.com/NetchX/Netch/workflows/Netch%20CI/badge.svg)](https://github.com/NetchX/Netch/actions)
[![网站](https://img.shields.io/website?url=https%3A%2F%2Fnetch.org)](https://netch.org/)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
游戏加速工具
@@ -69,9 +68,10 @@ Netch 支持多种语言,在启动时会根据系统语言选择自身语言
- [go-tun2socks](https://github.com/eycorsican/go-tun2socks)
- [shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev)
- [shadowsocksr-libev](https://github.com/shadowsocksrr/shadowsocksr-libev)
- [v2ray-core](https://github.com/v2ray/v2ray-core)
- [v2ray-core](https://github.com/v2fly/v2ray-core)
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [PAC](https://github.com/HMBSbige/Text_Translation/blob/master/ShadowsocksR/ss_white.pac)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)

2
modes

Submodule modes updated: 90ffd0c66a...25ec8156f9