mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d15206b803 | ||
|
|
754753300d | ||
|
|
aa021aaf79 | ||
|
|
c50ca563b2 | ||
|
|
a1fdf7ead2 | ||
|
|
c9da7197ba | ||
|
|
5ff26e97b4 | ||
|
|
06049cb06f | ||
|
|
8cf765de92 | ||
|
|
2b53a7ca9e | ||
|
|
c7c0a2a698 | ||
|
|
1d072214ee | ||
|
|
135ff642bd | ||
|
|
4c274a1888 | ||
|
|
59cfc071cc | ||
|
|
8cf32e5d37 | ||
|
|
7a1e5b58b9 | ||
|
|
651fbb6ff9 | ||
|
|
45bf31e9f3 | ||
|
|
f7c9ab4028 | ||
|
|
717dc55055 | ||
|
|
a0c4dd3192 | ||
|
|
325ad430fe | ||
|
|
4b374d3898 | ||
|
|
b6afeab187 | ||
|
|
6e499c3948 | ||
|
|
5bfcbab543 | ||
|
|
fe69c5a67b | ||
|
|
1c974d295b | ||
|
|
a544bd1a26 | ||
|
|
3bfe03b99b | ||
|
|
1fa18ce787 | ||
|
|
f7ad2baa52 | ||
|
|
447a25457b | ||
|
|
3a8351e6e4 | ||
|
|
eb30300b24 | ||
|
|
0b8373a21e | ||
|
|
8a551b715e | ||
|
|
34814fe7f5 | ||
|
|
528abe3fdd | ||
|
|
a10410dafd | ||
|
|
2ca98a94d5 |
@@ -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
|
||||
|
||||
@@ -2,10 +2,13 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
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
|
||||
@@ -14,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;
|
||||
@@ -33,13 +36,11 @@ namespace Netch.Controllers
|
||||
try
|
||||
{
|
||||
if (pPrivoxyController.Start(MainController.Server, mode))
|
||||
{
|
||||
Global.Job.AddProcess(pPrivoxyController.Instance);
|
||||
}
|
||||
|
||||
if (mode.Type == 3)
|
||||
{
|
||||
if (mode.BypassChina)
|
||||
if (MainController.Server is Socks5 or Trojan && mode.BypassChina)
|
||||
{
|
||||
//启动PAC服务器
|
||||
PACServerHandle.InitPACServer("127.0.0.1");
|
||||
@@ -66,35 +67,6 @@ namespace Netch.Controllers
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RecordPrevious()
|
||||
{
|
||||
try
|
||||
{
|
||||
var registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
|
||||
if (registry == null)
|
||||
throw new Exception();
|
||||
|
||||
prevPAC = registry.GetValue("AutoConfigURL")?.ToString() ?? "";
|
||||
prevHTTP = registry.GetValue("ProxyServer")?.ToString() ?? "";
|
||||
prevBypass = registry.GetValue("ProxyOverride")?.ToString() ?? "";
|
||||
prevEnabled = registry.GetValue("ProxyEnable")?.Equals(1) ?? false; // HTTP Proxy Enabled
|
||||
|
||||
if (prevHTTP == $"127.0.0.1:{Global.Settings.HTTPLocalPort}")
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevHTTP = "";
|
||||
}
|
||||
|
||||
if (prevPAC != "")
|
||||
prevEnabled = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevPAC = prevHTTP = prevBypass = "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
@@ -136,5 +108,34 @@ namespace Netch.Controllers
|
||||
};
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
private void RecordPrevious()
|
||||
{
|
||||
try
|
||||
{
|
||||
var registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
|
||||
if (registry == null)
|
||||
throw new Exception();
|
||||
|
||||
prevPAC = registry.GetValue("AutoConfigURL")?.ToString() ?? "";
|
||||
prevHTTP = registry.GetValue("ProxyServer")?.ToString() ?? "";
|
||||
prevBypass = registry.GetValue("ProxyOverride")?.ToString() ?? "";
|
||||
prevEnabled = registry.GetValue("ProxyEnable")?.Equals(1) ?? false; // HTTP Proxy Enabled
|
||||
|
||||
if (prevHTTP == $"127.0.0.1:{Global.Settings.HTTPLocalPort}")
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevHTTP = "";
|
||||
}
|
||||
|
||||
if (prevPAC != "")
|
||||
prevEnabled = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
prevEnabled = false;
|
||||
prevPAC = prevHTTP = prevBypass = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -13,6 +14,19 @@ 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 bool NttTested;
|
||||
|
||||
private static readonly NTTController NTTController = new();
|
||||
private static IServerController _serverController;
|
||||
private static IServerController _udpServerController;
|
||||
|
||||
public static IServerController ServerController
|
||||
{
|
||||
get => _serverController;
|
||||
@@ -25,24 +39,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>
|
||||
@@ -53,11 +57,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();
|
||||
@@ -86,20 +89,16 @@ 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();
|
||||
_ = Task.Run(Bandwidth.NetTraffic);
|
||||
_ = Task.Run(NatTest);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -112,7 +111,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}");
|
||||
@@ -137,35 +135,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)
|
||||
{
|
||||
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;
|
||||
@@ -179,26 +172,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;
|
||||
}
|
||||
@@ -211,7 +196,6 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
public static async Task Stop()
|
||||
{
|
||||
UsingPorts.Clear();
|
||||
StatusPortInfoText.Reset();
|
||||
|
||||
_ = Task.Run(() => NTTController.Stop());
|
||||
@@ -219,28 +203,33 @@ 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;
|
||||
}
|
||||
catch (PortReservedException)
|
||||
{
|
||||
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is reserved by system.", $"{portName} ({port})"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +238,8 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
public static void NatTest()
|
||||
{
|
||||
if (!Mode.TestNatRequired())
|
||||
return;
|
||||
NttTested = false;
|
||||
Task.Run(() =>
|
||||
{
|
||||
@@ -262,7 +253,9 @@ namespace Netch.Controllers
|
||||
Global.MainForm.NatTypeStatusText(result, country);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MainForm.NatTypeStatusText(result ?? "Error");
|
||||
}
|
||||
|
||||
NttTested = true;
|
||||
});
|
||||
|
||||
@@ -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())
|
||||
@@ -105,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>
|
||||
@@ -119,7 +131,6 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="clear"></param>
|
||||
@@ -161,9 +172,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
if (!File.Exists(SystemDriver))
|
||||
{
|
||||
return InstallDriver();
|
||||
}
|
||||
|
||||
var updateFlag = false;
|
||||
|
||||
@@ -178,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;
|
||||
@@ -267,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;
|
||||
@@ -299,7 +292,7 @@ namespace Netch.Controllers
|
||||
private static extern ulong aio_getDL();
|
||||
|
||||
|
||||
public enum NameList : int
|
||||
public enum NameList
|
||||
{
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERTCP,
|
||||
@@ -363,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
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.Socks5;
|
||||
using Netch.Utils.HttpProxyHandler;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
|
||||
@@ -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,16 +26,16 @@ 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 MainFile { get; protected set; } = "tun2socks.exe";
|
||||
|
||||
public override string Name { get; protected set; } = "tun2socks";
|
||||
public override string MainFile { get; protected set; } = "tun2socks.exe";
|
||||
|
||||
public bool Start(in Mode mode)
|
||||
{
|
||||
@@ -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())
|
||||
{
|
||||
@@ -126,10 +120,6 @@ namespace Netch.Controllers
|
||||
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;
|
||||
@@ -303,26 +287,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 +352,22 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
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";
|
||||
@@ -16,20 +19,20 @@ namespace Netch.Controllers
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2020";
|
||||
|
||||
public const string AssemblyVersion = @"1.7.0";
|
||||
public const string AssemblyVersion = @"1.7.2";
|
||||
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}\""
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
14
Netch/Forms/MainForm.Designer.cs
generated
14
Netch/Forms/MainForm.Designer.cs
generated
@@ -39,6 +39,7 @@
|
||||
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();
|
||||
@@ -170,7 +171,8 @@
|
||||
//
|
||||
this.SubscribeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ManageSubscribeLinksToolStripMenuItem,
|
||||
this.UpdateServersFromSubscribeLinksToolStripMenuItem});
|
||||
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);
|
||||
@@ -190,6 +192,13 @@
|
||||
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(294, 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[] {
|
||||
@@ -245,7 +254,7 @@
|
||||
this.UninstallTapDriverToolStripMenuItem.Name = "UninstallTapDriverToolStripMenuItem";
|
||||
this.UninstallTapDriverToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
|
||||
this.UninstallTapDriverToolStripMenuItem.Text = "Uninstall TUN/TAP driver";
|
||||
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.reinstallTapDriverToolStripMenuItem_Click);
|
||||
this.UninstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.UninstallTapDriverToolStripMenuItem_Click);
|
||||
//
|
||||
// HelpToolStripMenuItem
|
||||
//
|
||||
@@ -800,6 +809,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;
|
||||
|
||||
@@ -1,381 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
using Netch.Utils.HttpProxyHandler;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
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 updatePACToolStripMenuItem_Click(object sender, EventArgs eventArgs)
|
||||
{
|
||||
Enabled = false;
|
||||
|
||||
NotifyTip(i18N.Translate("Updating in the background"));
|
||||
try
|
||||
{
|
||||
var req = WebUtil.CreateRequest(Global.Settings.GFWLIST);
|
||||
|
||||
string gfwlist = Path.Combine(Global.NetchDir, $"bin\\gfwlist");
|
||||
string pac = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
|
||||
|
||||
await WebUtil.DownloadFileAsync(req, gfwlist);
|
||||
|
||||
var gfwContent = File.ReadAllText(gfwlist);
|
||||
List<string> lines = PACUtil.ParseResult(gfwContent);
|
||||
string abpContent = PACUtil.UnGzip(Resources.abp_js);
|
||||
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
|
||||
File.WriteAllText(pac, abpContent, Encoding.UTF8);
|
||||
|
||||
NotifyTip(i18N.Translate("PAC updated successfully"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NotifyTip(i18N.Translate("PAC update failed") + "\n" + e.Message, info: false);
|
||||
Logging.Error("更新 PAC 失败!" + e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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}\""
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Netch/Forms/SettingForm.Designer.cs
generated
113
Netch/Forms/SettingForm.Designer.cs
generated
@@ -49,9 +49,10 @@ namespace Netch.Forms
|
||||
this.ResolveServerHostnameCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ProfileCountLabel = new System.Windows.Forms.Label();
|
||||
this.ProfileCountTextBox = new System.Windows.Forms.TextBox();
|
||||
this.TcpingAtStartedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.DetectionIntervalLabel = new System.Windows.Forms.Label();
|
||||
this.DetectionIntervalTextBox = new System.Windows.Forms.TextBox();
|
||||
this.StartedPingLabel = new System.Windows.Forms.Label();
|
||||
this.DetectionTickLabel = new System.Windows.Forms.Label();
|
||||
this.StartedPingIntervalTextBox = new System.Windows.Forms.TextBox();
|
||||
this.DetectionTickTextBox = new System.Windows.Forms.TextBox();
|
||||
this.STUNServerLabel = new System.Windows.Forms.Label();
|
||||
this.STUN_ServerComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.AclLabel = new System.Windows.Forms.Label();
|
||||
@@ -105,7 +106,7 @@ namespace Netch.Forms
|
||||
this.RunAtStartupCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.CheckUpdateWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.CheckBetaUpdateCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UpdateServersWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.AioDNSTabPage = new System.Windows.Forms.TabPage();
|
||||
this.AioDNSRuleRuleLabel = new System.Windows.Forms.Label();
|
||||
this.AioDNSRulePathTextBox = new System.Windows.Forms.TextBox();
|
||||
@@ -154,9 +155,10 @@ namespace Netch.Forms
|
||||
this.GeneralTabPage.Controls.Add(this.ResolveServerHostnameCheckBox);
|
||||
this.GeneralTabPage.Controls.Add(this.ProfileCountLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.ProfileCountTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.TcpingAtStartedCheckBox);
|
||||
this.GeneralTabPage.Controls.Add(this.DetectionIntervalLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.DetectionIntervalTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.StartedPingLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.DetectionTickLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.StartedPingIntervalTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.DetectionTickTextBox);
|
||||
this.GeneralTabPage.Controls.Add(this.STUNServerLabel);
|
||||
this.GeneralTabPage.Controls.Add(this.STUN_ServerComboBox);
|
||||
this.GeneralTabPage.Controls.Add(this.AclLabel);
|
||||
@@ -173,7 +175,7 @@ namespace Netch.Forms
|
||||
// ServerPingTypeLabel
|
||||
//
|
||||
this.ServerPingTypeLabel.AutoSize = true;
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(217, 160);
|
||||
this.ServerPingTypeLabel.Location = new System.Drawing.Point(267, 66);
|
||||
this.ServerPingTypeLabel.Name = "ServerPingTypeLabel";
|
||||
this.ServerPingTypeLabel.Size = new System.Drawing.Size(89, 12);
|
||||
this.ServerPingTypeLabel.TabIndex = 16;
|
||||
@@ -182,26 +184,24 @@ namespace Netch.Forms
|
||||
// TCPingRadioBtn
|
||||
//
|
||||
this.TCPingRadioBtn.AutoSize = true;
|
||||
this.TCPingRadioBtn.Location = new System.Drawing.Point(376, 158);
|
||||
this.TCPingRadioBtn.Location = new System.Drawing.Point(332, 85);
|
||||
this.TCPingRadioBtn.Name = "TCPingRadioBtn";
|
||||
this.TCPingRadioBtn.Size = new System.Drawing.Size(59, 16);
|
||||
this.TCPingRadioBtn.TabIndex = 15;
|
||||
this.TCPingRadioBtn.TabStop = true;
|
||||
this.TCPingRadioBtn.Text = "TCPing";
|
||||
this.TCPingRadioBtn.UseVisualStyleBackColor = true;
|
||||
this.TCPingRadioBtn.CheckedChanged += new System.EventHandler(this.TCPingRadioBtn_CheckedChanged);
|
||||
//
|
||||
// ICMPingRadioBtn
|
||||
//
|
||||
this.ICMPingRadioBtn.AutoSize = true;
|
||||
this.ICMPingRadioBtn.Location = new System.Drawing.Point(312, 158);
|
||||
this.ICMPingRadioBtn.Location = new System.Drawing.Point(268, 85);
|
||||
this.ICMPingRadioBtn.Name = "ICMPingRadioBtn";
|
||||
this.ICMPingRadioBtn.Size = new System.Drawing.Size(65, 16);
|
||||
this.ICMPingRadioBtn.TabIndex = 14;
|
||||
this.ICMPingRadioBtn.TabStop = true;
|
||||
this.ICMPingRadioBtn.Text = "ICMPing";
|
||||
this.ICMPingRadioBtn.UseVisualStyleBackColor = true;
|
||||
this.ICMPingRadioBtn.CheckedChanged += new System.EventHandler(this.ICMPingRadioBtn_CheckedChanged);
|
||||
//
|
||||
// PortGroupBox
|
||||
//
|
||||
@@ -318,32 +318,39 @@ namespace Netch.Forms
|
||||
this.ProfileCountTextBox.TabIndex = 4;
|
||||
this.ProfileCountTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// TcpingAtStartedCheckBox
|
||||
// StartedPingLabel
|
||||
//
|
||||
this.TcpingAtStartedCheckBox.AutoSize = true;
|
||||
this.TcpingAtStartedCheckBox.Location = new System.Drawing.Point(15, 186);
|
||||
this.TcpingAtStartedCheckBox.Name = "TcpingAtStartedCheckBox";
|
||||
this.TcpingAtStartedCheckBox.Size = new System.Drawing.Size(156, 16);
|
||||
this.TcpingAtStartedCheckBox.TabIndex = 5;
|
||||
this.TcpingAtStartedCheckBox.Text = "Delay test after start";
|
||||
this.TcpingAtStartedCheckBox.UseVisualStyleBackColor = true;
|
||||
this.StartedPingLabel.AutoSize = true;
|
||||
this.StartedPingLabel.Location = new System.Drawing.Point(12, 187);
|
||||
this.StartedPingLabel.Name = "StartedPingLabel";
|
||||
this.StartedPingLabel.Size = new System.Drawing.Size(137, 12);
|
||||
this.StartedPingLabel.TabIndex = 5;
|
||||
this.StartedPingLabel.Text = "Delay test after start";
|
||||
//
|
||||
// DetectionIntervalLabel
|
||||
// DetectionTickLabel
|
||||
//
|
||||
this.DetectionIntervalLabel.AutoSize = true;
|
||||
this.DetectionIntervalLabel.Location = new System.Drawing.Point(217, 187);
|
||||
this.DetectionIntervalLabel.Name = "DetectionIntervalLabel";
|
||||
this.DetectionIntervalLabel.Size = new System.Drawing.Size(143, 12);
|
||||
this.DetectionIntervalLabel.TabIndex = 6;
|
||||
this.DetectionIntervalLabel.Text = "Detection interval(sec)";
|
||||
this.DetectionTickLabel.AutoSize = true;
|
||||
this.DetectionTickLabel.Location = new System.Drawing.Point(225, 160);
|
||||
this.DetectionTickLabel.Name = "DetectionTickLabel";
|
||||
this.DetectionTickLabel.Size = new System.Drawing.Size(119, 12);
|
||||
this.DetectionTickLabel.TabIndex = 6;
|
||||
this.DetectionTickLabel.Text = "Detection Tick(sec)";
|
||||
//
|
||||
// DetectionIntervalTextBox
|
||||
// StartedPingIntervalTextBox
|
||||
//
|
||||
this.DetectionIntervalTextBox.Location = new System.Drawing.Point(366, 184);
|
||||
this.DetectionIntervalTextBox.Name = "DetectionIntervalTextBox";
|
||||
this.DetectionIntervalTextBox.Size = new System.Drawing.Size(68, 21);
|
||||
this.DetectionIntervalTextBox.TabIndex = 7;
|
||||
this.DetectionIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.StartedPingIntervalTextBox.Location = new System.Drawing.Point(177, 184);
|
||||
this.StartedPingIntervalTextBox.Name = "StartedPingIntervalTextBox";
|
||||
this.StartedPingIntervalTextBox.Size = new System.Drawing.Size(68, 21);
|
||||
this.StartedPingIntervalTextBox.TabIndex = 7;
|
||||
this.StartedPingIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// DetectionTickTextBox
|
||||
//
|
||||
this.DetectionTickTextBox.Location = new System.Drawing.Point(366, 157);
|
||||
this.DetectionTickTextBox.Name = "DetectionTickTextBox";
|
||||
this.DetectionTickTextBox.Size = new System.Drawing.Size(68, 21);
|
||||
this.DetectionTickTextBox.TabIndex = 7;
|
||||
this.DetectionTickTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// STUNServerLabel
|
||||
//
|
||||
@@ -375,7 +382,7 @@ namespace Netch.Forms
|
||||
//
|
||||
this.AclAddrTextBox.Location = new System.Drawing.Point(120, 245);
|
||||
this.AclAddrTextBox.Name = "AclAddrTextBox";
|
||||
this.AclAddrTextBox.Size = new System.Drawing.Size(315, 21);
|
||||
this.AclAddrTextBox.Size = new System.Drawing.Size(314, 21);
|
||||
this.AclAddrTextBox.TabIndex = 11;
|
||||
this.AclAddrTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
@@ -444,7 +451,6 @@ namespace Netch.Forms
|
||||
this.ModifySystemDNSCheckBox.TabIndex = 0;
|
||||
this.ModifySystemDNSCheckBox.Text = "Modify System DNS";
|
||||
this.ModifySystemDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
this.ModifySystemDNSCheckBox.CheckedChanged += new System.EventHandler(this.ModifySystemDNSCheckBox_CheckedChanged);
|
||||
//
|
||||
// ModifiedDNSLabel
|
||||
//
|
||||
@@ -457,6 +463,7 @@ namespace Netch.Forms
|
||||
//
|
||||
// ModifiedDNSTextBox
|
||||
//
|
||||
this.ModifiedDNSTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.ModifySystemDNSCheckBox, "Checked", true));
|
||||
this.ModifiedDNSTextBox.Location = new System.Drawing.Point(264, 14);
|
||||
this.ModifiedDNSTextBox.Name = "ModifiedDNSTextBox";
|
||||
this.ModifiedDNSTextBox.Size = new System.Drawing.Size(194, 21);
|
||||
@@ -472,7 +479,6 @@ namespace Netch.Forms
|
||||
this.RedirectorSSCheckBox.TabIndex = 0;
|
||||
this.RedirectorSSCheckBox.Text = "Redirector SS";
|
||||
this.RedirectorSSCheckBox.UseVisualStyleBackColor = true;
|
||||
this.RedirectorSSCheckBox.CheckedChanged += new System.EventHandler(this.ModifySystemDNSCheckBox_CheckedChanged);
|
||||
//
|
||||
// TAPTabPage
|
||||
//
|
||||
@@ -569,6 +575,7 @@ namespace Netch.Forms
|
||||
//
|
||||
// TUNTAPDNSTextBox
|
||||
//
|
||||
this.TUNTAPDNSTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Enabled", this.UseCustomDNSCheckBox, "Checked", true));
|
||||
this.TUNTAPDNSTextBox.Location = new System.Drawing.Point(120, 110);
|
||||
this.TUNTAPDNSTextBox.Name = "TUNTAPDNSTextBox";
|
||||
this.TUNTAPDNSTextBox.Size = new System.Drawing.Size(294, 21);
|
||||
@@ -807,7 +814,7 @@ namespace Netch.Forms
|
||||
this.OtherTabPage.Controls.Add(this.RunAtStartupCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.CheckUpdateWhenOpenedCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.CheckBetaUpdateCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.UpdateSubscribeatWhenOpenedCheckBox);
|
||||
this.OtherTabPage.Controls.Add(this.UpdateServersWhenOpenedCheckBox);
|
||||
this.OtherTabPage.Location = new System.Drawing.Point(4, 25);
|
||||
this.OtherTabPage.Name = "OtherTabPage";
|
||||
this.OtherTabPage.Padding = new System.Windows.Forms.Padding(3);
|
||||
@@ -890,16 +897,16 @@ namespace Netch.Forms
|
||||
this.CheckBetaUpdateCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.CheckBetaUpdateCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// UpdateSubscribeatWhenOpenedCheckBox
|
||||
// UpdateServersWhenOpenedCheckBox
|
||||
//
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.AutoSize = true;
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.Location = new System.Drawing.Point(200, 94);
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.Name = "UpdateSubscribeatWhenOpenedCheckBox";
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.Size = new System.Drawing.Size(204, 16);
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.TabIndex = 7;
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.Text = "Update subscribeat when opened";
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.UpdateSubscribeatWhenOpenedCheckBox.UseVisualStyleBackColor = true;
|
||||
this.UpdateServersWhenOpenedCheckBox.AutoSize = true;
|
||||
this.UpdateServersWhenOpenedCheckBox.Location = new System.Drawing.Point(200, 94);
|
||||
this.UpdateServersWhenOpenedCheckBox.Name = "UpdateServersWhenOpenedCheckBox";
|
||||
this.UpdateServersWhenOpenedCheckBox.Size = new System.Drawing.Size(180, 16);
|
||||
this.UpdateServersWhenOpenedCheckBox.TabIndex = 7;
|
||||
this.UpdateServersWhenOpenedCheckBox.Text = "Update Servers when opened";
|
||||
this.UpdateServersWhenOpenedCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.UpdateServersWhenOpenedCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// AioDNSTabPage
|
||||
//
|
||||
@@ -970,7 +977,7 @@ namespace Netch.Forms
|
||||
//
|
||||
// ControlButton
|
||||
//
|
||||
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ControlButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ControlButton.Location = new System.Drawing.Point(397, 363);
|
||||
this.ControlButton.Name = "ControlButton";
|
||||
this.ControlButton.Size = new System.Drawing.Size(75, 23);
|
||||
@@ -1001,7 +1008,7 @@ namespace Netch.Forms
|
||||
this.ClientSize = new System.Drawing.Size(480, 400);
|
||||
this.Controls.Add(this.flowLayoutPanel1);
|
||||
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.MaximizeBox = false;
|
||||
this.Name = "SettingForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
@@ -1028,8 +1035,8 @@ namespace Netch.Forms
|
||||
this.flowLayoutPanel1.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
private System.Windows.Forms.TextBox StartedPingIntervalTextBox;
|
||||
private System.Windows.Forms.CheckBox NoProxyForTcpCheckBox;
|
||||
|
||||
#endregion
|
||||
@@ -1067,7 +1074,7 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.Button ControlButton;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.TabPage OtherTabPage;
|
||||
private System.Windows.Forms.CheckBox UpdateSubscribeatWhenOpenedCheckBox;
|
||||
private System.Windows.Forms.CheckBox UpdateServersWhenOpenedCheckBox;
|
||||
private System.Windows.Forms.CheckBox RunAtStartupCheckBox;
|
||||
private System.Windows.Forms.CheckBox MinimizeWhenStartedCheckBox;
|
||||
private System.Windows.Forms.CheckBox CheckBetaUpdateCheckBox;
|
||||
@@ -1079,9 +1086,9 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.ComboBox LanguageComboBox;
|
||||
private System.Windows.Forms.TextBox AclAddrTextBox;
|
||||
private System.Windows.Forms.Label AclLabel;
|
||||
private System.Windows.Forms.Label DetectionIntervalLabel;
|
||||
private System.Windows.Forms.TextBox DetectionIntervalTextBox;
|
||||
private System.Windows.Forms.CheckBox TcpingAtStartedCheckBox;
|
||||
private System.Windows.Forms.Label DetectionTickLabel;
|
||||
private System.Windows.Forms.TextBox DetectionTickTextBox;
|
||||
private System.Windows.Forms.Label StartedPingLabel;
|
||||
private System.Windows.Forms.Label STUNServerLabel;
|
||||
private System.Windows.Forms.ComboBox STUN_ServerComboBox;
|
||||
private System.Windows.Forms.Label ProfileCountLabel;
|
||||
|
||||
@@ -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);
|
||||
@@ -60,7 +61,7 @@ namespace Netch.Forms
|
||||
Global.Settings.ResolveServerHostname);
|
||||
|
||||
BindRadioBox(ICMPingRadioBtn,
|
||||
c => Global.Settings.ServerTCPing = c,
|
||||
_ => { },
|
||||
!Global.Settings.ServerTCPing);
|
||||
|
||||
BindRadioBox(TCPingRadioBtn,
|
||||
@@ -71,13 +72,14 @@ namespace Netch.Forms
|
||||
i => i > -1,
|
||||
i => Global.Settings.ProfileCount = i,
|
||||
Global.Settings.ProfileCount);
|
||||
BindCheckBox(TcpingAtStartedCheckBox,
|
||||
b => Global.Settings.StartedTcping = b,
|
||||
Global.Settings.StartedTcping);
|
||||
BindTextBox<int>(DetectionIntervalTextBox,
|
||||
BindTextBox<int>(DetectionTickTextBox,
|
||||
i => i >= 0,
|
||||
i => Global.Settings.StartedTcping_Interval = i,
|
||||
Global.Settings.StartedTcping_Interval);
|
||||
i => Global.Settings.DetectionTick = i,
|
||||
Global.Settings.DetectionTick);
|
||||
BindTextBox<int>(StartedPingIntervalTextBox,
|
||||
_ => true,
|
||||
i => Global.Settings.StartedPingInterval = i,
|
||||
Global.Settings.StartedPingInterval);
|
||||
|
||||
InitSTUN();
|
||||
|
||||
@@ -98,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,
|
||||
@@ -136,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),
|
||||
@@ -239,9 +238,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
|
||||
|
||||
@@ -267,21 +266,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
|
||||
@@ -318,9 +310,7 @@ namespace Netch.Forms
|
||||
}
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -337,9 +327,7 @@ namespace Netch.Forms
|
||||
stunServer = stun[0];
|
||||
if (stun.Length > 1)
|
||||
if (!ushort.TryParse(stun[1], out stunServerPort))
|
||||
{
|
||||
errFlag = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -357,9 +345,7 @@ namespace Netch.Forms
|
||||
#region Save
|
||||
|
||||
foreach (var pair in _saveActions)
|
||||
{
|
||||
pair.Value.Invoke(pair.Key);
|
||||
}
|
||||
|
||||
Global.Settings.STUN_Server = stunServer;
|
||||
Global.Settings.STUN_Server_Port = stunServerPort;
|
||||
@@ -428,23 +414,12 @@ 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));
|
||||
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
|
||||
}
|
||||
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
|
||||
{
|
||||
control.Checked = value;
|
||||
_checkActions.Add(control, s => true);
|
||||
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
|
||||
}
|
||||
|
||||
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
|
||||
|
||||
private readonly Dictionary<Control, Action<Control>> _saveActions = new Dictionary<Control, Action<Control>>();
|
||||
|
||||
private void ModifySystemDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ModifiedDNSTextBox.Enabled = ModifySystemDNSCheckBox.Checked;
|
||||
_saveActions.Add(control, c => save.Invoke(((RadioButton) c).Checked));
|
||||
}
|
||||
|
||||
private void NoProxyForUdpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
@@ -456,15 +431,5 @@ namespace Netch.Forms
|
||||
{
|
||||
if (NoProxyForTcpCheckBox.Checked) NoProxyForUdpCheckBox.Checked = false;
|
||||
}
|
||||
|
||||
private void ICMPingRadioBtn_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ICMPingRadioBtn.Checked) TCPingRadioBtn.Checked = false;
|
||||
}
|
||||
|
||||
private void TCPingRadioBtn_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (TCPingRadioBtn.Checked) ICMPingRadioBtn.Checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Netch/Forms/SubscribeForm.Designer.cs
generated
102
Netch/Forms/SubscribeForm.Designer.cs
generated
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,61 @@
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -66,20 +63,19 @@ namespace Netch.Models
|
||||
{
|
||||
public bool AllowInsecure = true;
|
||||
|
||||
public KcpConfig KcpConfig = new KcpConfig();
|
||||
public KcpConfig KcpConfig = new();
|
||||
|
||||
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>
|
||||
@@ -87,35 +83,62 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public class Setting
|
||||
{
|
||||
|
||||
public V2rayConfig V2RayConfig = new V2rayConfig();
|
||||
|
||||
public AioDNSConfig AioDNS = new AioDNSConfig();
|
||||
|
||||
/// <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>
|
||||
/// 是否启动后自动最小化
|
||||
@@ -123,29 +146,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
|
||||
@@ -153,19 +156,14 @@ 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 int RequestTimeout = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// PAC URL
|
||||
/// </summary>
|
||||
public string Pac_Url = "";
|
||||
public string PAC = "https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac";
|
||||
|
||||
/// <summary>
|
||||
/// PAC端口
|
||||
@@ -173,64 +171,84 @@ namespace Netch.Models
|
||||
public int Pac_Port = 2803;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 本地端口
|
||||
/// PAC URL
|
||||
/// </summary>
|
||||
public ushort HTTPLocalPort = 2802;
|
||||
public string Pac_Url = "";
|
||||
|
||||
/// <summary>
|
||||
/// Socks5 本地端口
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public ushort Socks5LocalPort = 2801;
|
||||
public bool ProcessNoProxyForTcp = false;
|
||||
|
||||
/// <summary>
|
||||
/// Redirector TCP 占用端口
|
||||
/// 不代理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>
|
||||
/// UDP Socket 占用端口
|
||||
/// 网页请求超时 毫秒
|
||||
/// </summary>
|
||||
public ushort UDPSocketPort = 18291;
|
||||
public int RequestTimeout = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 和 Socks5 本地代理地址
|
||||
/// 解析服务器主机名
|
||||
/// </summary>
|
||||
public string LocalAddress = "127.0.0.1";
|
||||
public bool ResolveServerHostname = false;
|
||||
|
||||
/// <summary>
|
||||
/// TUNTAP 适配器配置
|
||||
/// 是否开机启动软件
|
||||
/// </summary>
|
||||
public TUNTAPConfig TUNTAP = new TUNTAPConfig();
|
||||
public bool RunAtStartup = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用代理更新订阅
|
||||
/// 服务器选择位置
|
||||
/// </summary>
|
||||
public bool UseProxyToUpdateSubscription = false;
|
||||
public int ServerComboBoxSelectedIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 订阅链接列表
|
||||
/// 服务器测试方式 false.ICMPing true.TCPing
|
||||
/// </summary>
|
||||
public List<SubscribeLink> SubscribeLink = new List<SubscribeLink>();
|
||||
public bool ServerTCPing = true;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器列表
|
||||
/// Socks5 本地端口
|
||||
/// </summary>
|
||||
public readonly List<Server> Server = new List<Server>();
|
||||
public ushort Socks5LocalPort = 2801;
|
||||
|
||||
/// <summary>
|
||||
/// 全局绕过 IP 列表
|
||||
/// 启动后延迟测试间隔/秒
|
||||
/// </summary>
|
||||
public List<string> BypassIPs = new List<string>();
|
||||
public int StartedPingInterval = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 已保存的快捷配置
|
||||
/// 是否打开软件时启动加速
|
||||
/// </summary>
|
||||
public List<Profile> Profiles = new List<Profile>();
|
||||
public bool StartWhenOpened = false;
|
||||
|
||||
/// <summary>
|
||||
/// 快捷配置数量
|
||||
/// 是否退出时停止
|
||||
/// </summary>
|
||||
public int ProfileCount = 4;
|
||||
public bool StopWhenExited = false;
|
||||
|
||||
/// <summary>
|
||||
/// STUN测试服务器
|
||||
@@ -243,53 +261,30 @@ 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>
|
||||
/// GFWList
|
||||
/// 是否打开软件时更新订阅
|
||||
/// </summary>
|
||||
public string GFWLIST = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";
|
||||
public bool UpdateServersWhenOpened = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用DLL启动Shadowsocks
|
||||
/// 使用代理更新订阅
|
||||
/// </summary>
|
||||
public bool BootShadowsocksFromDLL = true;
|
||||
public bool UseProxyToUpdateSubscription = false;
|
||||
|
||||
/// <summary>
|
||||
/// 语言设置
|
||||
/// </summary>
|
||||
public string Language = "System";
|
||||
|
||||
/// <summary>
|
||||
/// 服务器测试方式 false.ICMPing true.TCPing
|
||||
/// </summary>
|
||||
public bool ServerTCPing = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用RDR内置SS
|
||||
/// </summary>
|
||||
public bool RedirectorSS = false;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理UDP
|
||||
/// </summary>
|
||||
public bool ProcessNoProxyForUdp = false;
|
||||
|
||||
/// <summary>
|
||||
/// 不代理TCP
|
||||
/// </summary>
|
||||
public bool ProcessNoProxyForTcp = false;
|
||||
public V2rayConfig V2RayConfig = new();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
{
|
||||
public class SubscribeLink
|
||||
{
|
||||
/// <summary>
|
||||
/// 启用状态
|
||||
/// </summary>
|
||||
public bool Enable = true;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
@@ -17,4 +22,4 @@
|
||||
/// </summary>
|
||||
public string UserAgent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,7 +25,7 @@ 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);
|
||||
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
|
||||
@@ -21,3 +21,5 @@ 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
|
||||
|
||||
exit 0
|
||||
@@ -28,7 +28,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 +66,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,16 +89,16 @@
|
||||
"Modes have been reload": "模式已重载",
|
||||
"Clean DNS Cache": "清理 DNS 缓存",
|
||||
"DNS cache cleanup succeeded": "DNS 缓存清理成功",
|
||||
|
||||
|
||||
"Update PAC": "更新 PAC",
|
||||
"PAC updated successfully": "PAC 更新成功",
|
||||
"PAC update failed": "PAC 更新失败",
|
||||
|
||||
|
||||
"Update ACL": "更新 ACL 规则",
|
||||
"Update ACL with proxy": "使用代理更新 ACL 规则",
|
||||
"ACL updated successfully": "ACL 更新成功",
|
||||
"ACL update failed": "ACL 更新失败",
|
||||
|
||||
|
||||
"Open Directory": "打开目录",
|
||||
|
||||
"About": "关于",
|
||||
@@ -119,9 +127,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": "模式修改成功",
|
||||
@@ -155,18 +164,18 @@
|
||||
"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 Tcp": "不代理Tcp流量",
|
||||
"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": "启动后延迟测试",
|
||||
@@ -189,6 +198,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": "[不设置代理] 绕过局域网",
|
||||
@@ -196,4 +206,4 @@
|
||||
"[Web Proxy] Bypass LAN and China": "[网页代理] 绕过局域网和中国大陆",
|
||||
"[Non Web Proxy] Bypass LAN and China": "[不设置代理] 绕过局域网和中国大陆",
|
||||
"[TUN/TAP] Bypass LAN and China": "[TUN/TAP] 绕过局域网和中国大陆"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Text;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
using Netch.Servers.VMess;
|
||||
|
||||
namespace Netch.Servers.VLESS
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Netch.Forms;
|
||||
using Netch.Properties;
|
||||
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供PAC功能支持
|
||||
/// </summary>
|
||||
class PACUtil
|
||||
{
|
||||
private static readonly IEnumerable<char> IgnoredLineBegins = new[] {'!', '['};
|
||||
|
||||
public static List<string> ParseResult(string response)
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(response);
|
||||
string content = Encoding.ASCII.GetString(bytes);
|
||||
List<string> valid_lines = new List<string>();
|
||||
using (var sr = new StringReader(content))
|
||||
{
|
||||
foreach (var line in sr.NonWhiteSpaceLines())
|
||||
{
|
||||
if (line.BeginWithAny(IgnoredLineBegins))
|
||||
continue;
|
||||
valid_lines.Add(line);
|
||||
}
|
||||
}
|
||||
return valid_lines;
|
||||
}
|
||||
|
||||
public static string UnGzip(byte[] buf)
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int n;
|
||||
using (MemoryStream sb = new MemoryStream())
|
||||
{
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(buf),
|
||||
CompressionMode.Decompress,
|
||||
false))
|
||||
{
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
sb.Write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
return System.Text.Encoding.UTF8.GetString(sb.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using Netch.Controllers;
|
||||
using Netch.Models.WinFW;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -8,15 +8,16 @@ 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 +25,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,48 +49,22 @@ 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,101 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly struct Range
|
||||
{
|
||||
public int Start { get; }
|
||||
|
||||
public int End { get; }
|
||||
|
||||
public Range(int start, int end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录Netch使用的端口
|
||||
/// </summary>
|
||||
public static readonly List<ushort> UsingPorts = new List<ushort>();
|
||||
public bool InRange(int num)
|
||||
{
|
||||
return Start <= num && num <= End;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -145,4 +182,7 @@ namespace Netch.Utils
|
||||
public class PortInUseException : Exception
|
||||
{
|
||||
}
|
||||
public class PortReservedException : Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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,79 @@ 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;
|
||||
static DelayTestHelper()
|
||||
{
|
||||
Timer = new Timer
|
||||
{
|
||||
Interval = 10000,
|
||||
AutoReset = true,
|
||||
Enabled = false
|
||||
};
|
||||
|
||||
Timer.Elapsed += (_, _) => TestAllDelay();
|
||||
}
|
||||
|
||||
public static bool Enabled
|
||||
{
|
||||
get => Timer.Enabled;
|
||||
set => Timer.Enabled = value;
|
||||
}
|
||||
|
||||
public static int Interval => (int) (Timer.Interval / 1000);
|
||||
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()
|
||||
{
|
||||
var enabled = Enabled;
|
||||
Timer.Stop();
|
||||
if (Global.Settings.DetectionTick <= 0)
|
||||
return;
|
||||
|
||||
Timer.Interval = Global.Settings.DetectionTick * 1000;
|
||||
if (enabled)
|
||||
{
|
||||
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 +114,7 @@ namespace Netch.Utils
|
||||
{
|
||||
return ServerUtils.FirstOrDefault(i => i.UriScheme.Any(s => s.Equals(typeName)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -216,6 +216,14 @@ 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>())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/actions)
|
||||
[](https://netch.org/)
|
||||
[](LICENSE)
|
||||
|
||||
[中文说明](/docs/README.zh-CN.md)
|
||||
@@ -60,10 +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)
|
||||
- [GFWList](https://github.com/gfwlist/gfwlist)
|
||||
- [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
binaries
2
binaries
Submodule binaries updated: 859ff7b19c...7d34d180e3
@@ -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
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/actions)
|
||||
[](https://netch.org/)
|
||||
[](LICENSE)
|
||||
|
||||
游戏加速工具
|
||||
@@ -69,10 +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)
|
||||
- [GFWList](https://github.com/gfwlist/gfwlist)
|
||||
- [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/)
|
||||
|
||||
Reference in New Issue
Block a user