mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Compare commits
36 Commits
1.5.1
...
1.6.0-Beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5836f87537 | ||
|
|
12780e5116 | ||
|
|
ecd1257a35 | ||
|
|
49e2eb6a56 | ||
|
|
8ee86c3996 | ||
|
|
9b12ae9462 | ||
|
|
801e8e3b8a | ||
|
|
74f136bd93 | ||
|
|
e9a1750871 | ||
|
|
626192c5ea | ||
|
|
8b7ce23a82 | ||
|
|
48d543ce65 | ||
|
|
dbc45a2562 | ||
|
|
b3f8b863e2 | ||
|
|
becc6d8187 | ||
|
|
f777fae3d8 | ||
|
|
383efc453d | ||
|
|
83096c3f11 | ||
|
|
e8c1bcb74b | ||
|
|
76aa32967f | ||
|
|
082803469d | ||
|
|
7d47122b37 | ||
|
|
27f4768f24 | ||
|
|
9f4a974a3c | ||
|
|
a89efdb0d7 | ||
|
|
04fd88ea3c | ||
|
|
c9527e8671 | ||
|
|
5a431710ad | ||
|
|
c305473793 | ||
|
|
c4f06eb45d | ||
|
|
664cff4e52 | ||
|
|
20990e537c | ||
|
|
1d33dda9bc | ||
|
|
116d5418d1 | ||
|
|
cdaa1fbc25 | ||
|
|
7458b7b4cd |
43
.github/jetbrains-variant-4.svg
vendored
Normal file
43
.github/jetbrains-variant-4.svg
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="263" height="147" viewBox="0 0 263 147">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="54.4568" y1="122.5936" x2="251.779" y2="10.2057" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#00adee"/>
|
||||
<stop offset="1" stop-color="#9f76a6"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="80.247" y1="38.7607" x2="241.2622" y2="10.9511" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ec037c"/>
|
||||
<stop offset="1" stop-color="#9f76a6"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="75.7205" y1="33.5582" x2="127.8253" y2="123.9392" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ec037c"/>
|
||||
<stop offset="1" stop-color="#5c2d90"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-4" x1="7.4647" y1="44.578" x2="129.4543" y2="125.0813" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#44c7f4"/>
|
||||
<stop offset="1" stop-color="#5c2d90"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g>
|
||||
<path d="M261.1839,10.3622a9.6784,9.6784,0,0,0-14.7448-8.2463l0-.0006L20.6942,136.0746h0a4.6974,4.6974,0,1,0,4.1326,8.4348h0q0.09-.0467.1784-0.097l230.5273-125.25a9.653,9.653,0,0,0,1.1508-.6253l0.0332-.018-0.0014-.0023A9.6682,9.6682,0,0,0,261.1839,10.3622Z" fill="url(#linear-gradient)"/>
|
||||
<path d="M261.1839,10.3622A9.6782,9.6782,0,0,0,251.5057.684q-0.2747,0-.5456.0157-0.25.0143-.4975,0.041L76.7981,25.4187A13.7347,13.7347,0,1,0,83.5355,51.983L252.8044,19.9512a9.6363,9.6363,0,0,0,1.0358-.196l0.02-.0039,0-.0008A9.6811,9.6811,0,0,0,261.1839,10.3622Z" fill="url(#linear-gradient-2)"/>
|
||||
<path d="M145.2028,123.63a17.2372,17.2372,0,0,0-3.0637-9.4254L91.3045,32.3521A13.7366,13.7366,0,0,0,66.1132,42.9507h0a13.6332,13.6332,0,0,0,1.043,2.4984s45.2334,86.37,45.5824,86.9979q0.3089,0.556.6567,1.0861h0A17.32,17.32,0,0,0,145.2028,123.63Z" fill="url(#linear-gradient-3)"/>
|
||||
<path d="M145.2028,123.63a17.2979,17.2979,0,0,0-7.63-13.9419h0a17.3061,17.3061,0,0,0-2.6994-1.4911L9.5484,38.9679a6.064,6.064,0,0,0-6.5074,10.187l114.3963,88.704A17.3191,17.3191,0,0,0,145.2028,123.63Z" fill="url(#linear-gradient-4)"/>
|
||||
<g>
|
||||
<rect x="69" y="51" width="70" height="70"/>
|
||||
<g>
|
||||
<rect x="75.038" y="107.8746" width="26.2498" height="4.375" fill="#fff"/>
|
||||
<g>
|
||||
<path d="M74.7429,69.4315L76.78,67.5082a2.31,2.31,0,0,0,1.7929,1.0594A1.33,1.33,0,0,0,79.8607,66.97V59.75h3.1456v7.2366a4.2386,4.2386,0,0,1-1.1246,3.2108,4.2989,4.2989,0,0,1-3.1293,1.1572A4.6592,4.6592,0,0,1,74.7429,69.4315Z" fill="#fff"/>
|
||||
<path d="M83.7394,59.75h9.1761v2.673H86.8688v1.744H92.345v2.4937H86.8688V68.47H92.997v2.6893H83.7394V59.75Z" fill="#fff"/>
|
||||
<path d="M97.049,62.5208H93.6426V59.75h9.9911v2.7708h-3.4227v8.6383H97.049V62.5208Z" fill="#fff"/>
|
||||
<path d="M75.0363,73.8257h5.8511A4.2728,4.2728,0,0,1,84,74.8363a2.5675,2.5675,0,0,1,.7335,1.858v0.0326a2.6407,2.6407,0,0,1-1.76,2.5425,2.7686,2.7686,0,0,1,2.2655,2.7871v0.0326c0,1.9558-1.5973,3.1456-4.3191,3.1456H75.0363V73.8257Zm6.5846,3.5206c0-.6357-0.5052-0.9779-1.4343-0.9779h-2.07v2.0047h1.9884c0.9616,0,1.5158-.326,1.5158-0.9942V77.3463ZM80.5289,80.59H78.1166v2.1025h2.4448c0.9779,0,1.5158-.3749,1.5158-1.0431V81.6165C82.0773,80.9972,81.5883,80.59,80.5289,80.59Z" fill="#fff"/>
|
||||
<path d="M85.7116,73.8257h5.3949a5.0512,5.0512,0,0,1,3.7161,1.2224,3.5623,3.5623,0,0,1,1.01,2.6567v0.0326a3.6146,3.6146,0,0,1-2.3469,3.5205l2.7218,3.9769H92.5733l-2.2981-3.4553H88.8735v3.4553H85.7116V73.8257Zm5.2644,5.4764a1.433,1.433,0,0,0,1.6951-1.3528V77.9167c0-.9128-0.6682-1.3691-1.7114-1.3691H88.8735v2.7545H90.976Z" fill="#fff"/>
|
||||
<path d="M99.5324,73.7443H102.58l4.8571,11.4905h-3.39l-0.815-2.0536H98.8153L98,85.2348H94.6917Zm2.7707,6.9758-1.2712-3.2271L99.7443,80.72h2.5589Z" fill="#fff"/>
|
||||
<path d="M107.8117,73.8257h3.1619V85.2348h-3.1619V73.8257Z" fill="#fff"/>
|
||||
<path d="M111.7558,73.8257h2.95l4.694,6.0306V73.8257h3.1294V85.2348h-2.7545l-4.89-6.2587v6.2587h-3.1293V73.8257Z" fill="#fff"/>
|
||||
<path d="M122.7274,83.54l1.76-2.1025a5.9106,5.9106,0,0,0,3.7,1.3691c0.8638,0,1.32-.2934,1.32-0.7824V81.9914c0-.489-0.3749-0.7335-1.9395-1.1084-2.4285-.5541-4.3029-1.2387-4.3029-3.5694V77.2811c0-2.1188,1.6788-3.6509,4.417-3.6509a7.1807,7.1807,0,0,1,4.694,1.5158l-1.5809,2.2329a5.6006,5.6006,0,0,0-3.1946-1.1246c-0.766,0-1.1409.31-1.1409,0.7334V77.02c0,0.5216.3912,0.75,1.9884,1.1083,2.6077,0.57,4.2377,1.418,4.2377,3.5531v0.0326c0,2.3307-1.8418,3.7161-4.6126,3.7161A7.9992,7.9992,0,0,1,122.7274,83.54Z" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Netch.Utils;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -8,8 +9,7 @@ namespace Netch.Controllers
|
||||
public DNSController()
|
||||
{
|
||||
Name = "DNS Service";
|
||||
MainFile = "unbound.exe";
|
||||
// RedirectStd = false;
|
||||
RedirectStd = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -18,12 +18,31 @@ namespace Netch.Controllers
|
||||
/// <returns></returns>
|
||||
public bool Start()
|
||||
{
|
||||
return StartInstanceAuto("-c unbound-service.conf -v");
|
||||
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath("bin\\china_site_list")),
|
||||
Encoding.UTF8.GetBytes("223.5.5.5:53"),
|
||||
Encoding.UTF8.GetBytes("1.1.1.1:53"))
|
||||
)
|
||||
return false;
|
||||
return
|
||||
aiodns_init();
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
aiodns_free();
|
||||
}
|
||||
|
||||
#region NativeMethods
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_dial(byte[] chinacon, byte[] chinadns, byte[] otherdns);
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_init();
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void aiodns_free();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class SSController : EncryptedProxy
|
||||
{
|
||||
private bool dllFlag = false;
|
||||
|
||||
public SSController()
|
||||
{
|
||||
Name = "Shadowsocks";
|
||||
MainFile = "Shadowsocks.exe";
|
||||
StartedKeywords.Add("listening at");
|
||||
StoppedKeywords.AddRange(new[] {"Invalid config path", "usage", "plugin service exit unexpectedly"});
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
{
|
||||
//从DLL启动Shaowsocks
|
||||
if (Global.Settings.BootShadowsocksFromDLL && (mode.Type == 0 || mode.Type == 1 || mode.Type == 2))
|
||||
{
|
||||
dllFlag = true;
|
||||
State = State.Starting;
|
||||
var client = Encoding.UTF8.GetBytes($"{LocalAddress}:{Socks5LocalPort}");
|
||||
var remote = Encoding.UTF8.GetBytes($"{server.Hostname}:{server.Port}");
|
||||
var passwd = Encoding.UTF8.GetBytes($"{server.Password}");
|
||||
var method = Encoding.UTF8.GetBytes($"{server.EncryptMethod}");
|
||||
if (!NativeMethods.Shadowsocks.Info(client, remote, passwd, method))
|
||||
{
|
||||
State = State.Stopped;
|
||||
Logging.Error("DLL SS INFO 设置失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS INFO 设置成功!");
|
||||
|
||||
if (!NativeMethods.Shadowsocks.Start())
|
||||
{
|
||||
State = State.Stopped;
|
||||
Logging.Error("DLL SS 启动失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS 启动成功!");
|
||||
State = State.Started;
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Argument
|
||||
|
||||
var argument = new StringBuilder();
|
||||
argument.Append(
|
||||
$"-s {server.Hostname} -p {server.Port} -b {LocalAddress} -l {Socks5LocalPort} -m {server.EncryptMethod} -k \"{server.Password}\" -u");
|
||||
if (!string.IsNullOrWhiteSpace(server.Plugin) && !string.IsNullOrWhiteSpace(server.PluginOption))
|
||||
argument.Append($" --plugin {server.Plugin} --plugin-opts \"{server.PluginOption}\"");
|
||||
if (mode.BypassChina) argument.Append(" --acl default.acl");
|
||||
|
||||
#endregion
|
||||
|
||||
return StartInstanceAuto(argument.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSController 停止
|
||||
/// </summary>
|
||||
public override void Stop()
|
||||
{
|
||||
if (dllFlag) NativeMethods.Shadowsocks.Stop();
|
||||
else
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
184
Netch/Controllers/ICSController.cs
Normal file
184
Netch/Controllers/ICSController.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Management;
|
||||
using Netch.Utils;
|
||||
using NETCONLib;
|
||||
using WinFW;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class ICSController
|
||||
{
|
||||
public static bool Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
TUNTAPController.SearchTapAdapter();
|
||||
foreach (NetworkConnection connection in new NetworkConnectionCollection())
|
||||
{
|
||||
if (connection.DeviceName == Global.TUNTAP.Adapter.Description)
|
||||
{
|
||||
return connection.SharingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Enable()
|
||||
{
|
||||
Utils.Utils.SearchOutboundAdapter();
|
||||
TUNTAPController.SearchTapAdapter();
|
||||
|
||||
if (Global.TUNTAP.Adapter == null || Global.Outbound.Adapter == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CleanupWMISharingEntries();
|
||||
|
||||
#region Save Outbound IP Config
|
||||
|
||||
var wmi = new ManagementClass("Win32_NetworkAdapterConfiguration");
|
||||
var moc = wmi.GetInstances();
|
||||
|
||||
var dhcpEnabled = true;
|
||||
string[] ipAddress = null;
|
||||
string[] subnetMask = null;
|
||||
string[] gateway = null;
|
||||
ushort[] gatewayMetric = null;
|
||||
string[] dns = null;
|
||||
|
||||
var outboundWmi = GetManagementObjectByDeviceNameOrDefault(Global.Outbound.Adapter.Description);
|
||||
|
||||
if (outboundWmi == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(dhcpEnabled = (bool) outboundWmi["DHCPEnabled"]))
|
||||
{
|
||||
ipAddress = (string[]) outboundWmi["IPAddress"];
|
||||
subnetMask = (string[]) outboundWmi["IPSubnet"];
|
||||
gateway = (string[]) outboundWmi["DefaultIPGateway"];
|
||||
gatewayMetric = (ushort[]) outboundWmi["GatewayCostMetric"];
|
||||
dns = (string[]) outboundWmi["DNSServerSearchOrder"];
|
||||
|
||||
ipAddress = new[] {ipAddress[0]};
|
||||
subnetMask = new[] {subnetMask[0]};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Setting ICS
|
||||
|
||||
foreach (NetworkConnection connection in new NetworkConnectionCollection())
|
||||
{
|
||||
if (connection.DeviceName == Global.TUNTAP.Adapter.Description)
|
||||
{
|
||||
if (connection.SharingEnabled)
|
||||
connection.DisableSharing();
|
||||
connection.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PUBLIC);
|
||||
}
|
||||
else if (connection.DeviceName == Global.Outbound.Adapter.Description)
|
||||
{
|
||||
if (connection.SharingEnabled)
|
||||
connection.DisableSharing();
|
||||
connection.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reset Outbound IP Config
|
||||
|
||||
if (dhcpEnabled)
|
||||
{
|
||||
outboundWmi.InvokeMethod("EnableDHCP", null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set static IP and subnet mask
|
||||
var newIP = outboundWmi.GetMethodParameters("EnableStatic");
|
||||
newIP["IPAddress"] = ipAddress;
|
||||
newIP["SubnetMask"] = subnetMask;
|
||||
outboundWmi.InvokeMethod("EnableStatic", newIP, null);
|
||||
//Set default gateway
|
||||
var newGateway = outboundWmi.GetMethodParameters("SetGateways");
|
||||
newGateway["DefaultIPGateway"] = gateway;
|
||||
newGateway["GatewayCostMetric"] = gatewayMetric;
|
||||
outboundWmi.InvokeMethod("SetGateways", newGateway, null);
|
||||
//Set dns servers
|
||||
var newDNS = outboundWmi.GetMethodParameters("SetDNSServerSearchOrder");
|
||||
newDNS["DNSServerSearchOrder"] = dns;
|
||||
outboundWmi.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Disable();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Logging.Error($"网络连接共享设置失败: {e}");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Disable()
|
||||
{
|
||||
foreach (NetworkConnection connection in new NetworkConnectionCollection())
|
||||
{
|
||||
if (connection.SharingEnabled)
|
||||
connection.DisableSharing();
|
||||
}
|
||||
|
||||
CleanupWMISharingEntries();
|
||||
}
|
||||
|
||||
private static void CleanupWMISharingEntries()
|
||||
{
|
||||
var scope = new ManagementScope("root\\Microsoft\\HomeNet");
|
||||
scope.Connect();
|
||||
|
||||
var options = new PutOptions();
|
||||
options.Type = PutType.UpdateOnly;
|
||||
|
||||
var query = new ObjectQuery("SELECT * FROM HNet_ConnectionProperties");
|
||||
var srchr = new ManagementObjectSearcher(scope, query);
|
||||
foreach (ManagementObject entry in srchr.Get())
|
||||
{
|
||||
if ((bool) entry["IsIcsPrivate"])
|
||||
entry["IsIcsPrivate"] = false;
|
||||
if ((bool) entry["IsIcsPublic"])
|
||||
entry["IsIcsPublic"] = false;
|
||||
entry.Put(options);
|
||||
}
|
||||
}
|
||||
|
||||
public static ManagementObject GetManagementObjectByDeviceNameOrDefault(string deviceName)
|
||||
{
|
||||
foreach (ManagementObject mo in new ManagementClass("Win32_NetworkAdapterConfiguration").GetInstances())
|
||||
{
|
||||
if (((string) mo["Caption"]).EndsWith(deviceName))
|
||||
{
|
||||
return mo;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
@@ -161,7 +161,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly System.Timers.Timer SaveBufferTimer = new System.Timers.Timer(300) {AutoReset = true};
|
||||
private static readonly Timer SaveBufferTimer = new Timer(300) {AutoReset = true};
|
||||
|
||||
private void OnExited(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.Controllers
|
||||
@@ -8,9 +7,11 @@ namespace Netch.Controllers
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="s">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public abstract bool Start(Server server, Mode mode);
|
||||
public abstract bool Start(Server s, Mode mode);
|
||||
|
||||
public abstract bool TestNatRequired { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,76 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using static Netch.Forms.MainForm;
|
||||
using static Netch.Utils.PortHelper;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public static class MainController
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录当前使用的端口
|
||||
/// <see cref="MainForm.LocalPortText"/>
|
||||
/// </summary>
|
||||
public static readonly List<int> UsingPorts = new List<int>();
|
||||
|
||||
public static EncryptedProxy EncryptedProxyController { get; private set; }
|
||||
|
||||
public static ServerController ServerController { get; private set; }
|
||||
public static ModeController ModeController { get; private set; }
|
||||
|
||||
private static Server _savedServer;
|
||||
private static Mode _savedMode;
|
||||
public static bool NttTested;
|
||||
|
||||
public static string PortInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_savedMode == null || _savedServer == null)
|
||||
return string.Empty;
|
||||
|
||||
if (_savedServer.Type == "Socks5" && _savedMode.Type != 3 && _savedMode.Type != 5)
|
||||
// 不可控Socks5, 不可控HTTP
|
||||
return string.Empty;
|
||||
|
||||
var text = new StringBuilder();
|
||||
if (_localAddress == "0.0.0.0")
|
||||
text.Append(i18N.Translate("Allow other Devices to connect") + " ");
|
||||
|
||||
if (_savedServer.Type != "Socks5")
|
||||
// 可控Socks5
|
||||
text.Append($"Socks5 {i18N.Translate("Local Port", ": ")}{_socks5Port}");
|
||||
|
||||
if (_savedMode.Type == 3 || _savedMode.Type == 5)
|
||||
// 有HTTP
|
||||
{
|
||||
if (_savedServer.Type != "Socks5")
|
||||
text.Append(" | ");
|
||||
text.Append($"HTTP {i18N.Translate("Local Port", ": ")}{_httpPort}");
|
||||
}
|
||||
|
||||
return $" ({text})";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NTT 控制器
|
||||
/// </summary>
|
||||
public static readonly NTTController NTTController = new NTTController();
|
||||
|
||||
private static string _localAddress;
|
||||
private static int _redirectorTCPPort;
|
||||
private static int _httpPort;
|
||||
private static int _socks5Port;
|
||||
|
||||
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint FlushDNSResolverCache();
|
||||
private static readonly NTTController NTTController = new NTTController();
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
@@ -82,146 +27,54 @@ namespace Netch.Controllers
|
||||
{
|
||||
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
|
||||
#region Record Settings
|
||||
if (server.IsSocks5() && mode.Type == 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_httpPort = Global.Settings.HTTPLocalPort;
|
||||
_socks5Port = server.Type != "Socks5" ? Global.Settings.Socks5LocalPort : server.Port;
|
||||
_redirectorTCPPort = Global.Settings.RedirectorTCPPort;
|
||||
_localAddress = server.Type != "Socks5" ? Global.Settings.LocalAddress : "127.0.0.1";
|
||||
_savedServer = server;
|
||||
_savedMode = mode;
|
||||
NativeMethods.FlushDNSResolverCache();
|
||||
|
||||
#endregion
|
||||
if (!Utils.Utils.SearchOutboundAdapter(false))
|
||||
{
|
||||
MessageBoxX.Show("No internet connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
FlushDNSResolverCache();
|
||||
_ = Task.Run(Firewall.AddNetchFwRules);
|
||||
|
||||
bool result;
|
||||
if (server.Type == "Socks5")
|
||||
try
|
||||
{
|
||||
result = mode.Type != 4;
|
||||
if (!await StartServer(server, mode))
|
||||
{
|
||||
throw new StartFailedException();
|
||||
}
|
||||
|
||||
if (!await StartMode(server, mode))
|
||||
{
|
||||
throw new StartFailedException();
|
||||
}
|
||||
|
||||
if (ModeController.TestNatRequired)
|
||||
NatTest();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
EncryptedProxyController = server.Type switch
|
||||
switch (e)
|
||||
{
|
||||
"SS" => new SSController(),
|
||||
"SSR" => new SSRController(),
|
||||
"VMess" => new VMessController(),
|
||||
"Trojan" => new TrojanController(),
|
||||
_ => EncryptedProxyController
|
||||
};
|
||||
|
||||
KillProcessByName(EncryptedProxyController.MainFile);
|
||||
|
||||
#region 检查端口是否被占用
|
||||
|
||||
var portNotAvailable = false;
|
||||
if (_savedServer.Type != "Socks5")
|
||||
{
|
||||
portNotAvailable |= PortCheckAndShowMessageBox(_socks5Port, "Socks5");
|
||||
}
|
||||
|
||||
switch (_savedMode.Type)
|
||||
{
|
||||
case 0:
|
||||
portNotAvailable |= PortCheckAndShowMessageBox(_redirectorTCPPort, "Redirector TCP");
|
||||
case DllNotFoundException _:
|
||||
case FileNotFoundException _:
|
||||
MessageBoxX.Show(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"), owner: Global.MainForm);
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
portNotAvailable |= PortCheckAndShowMessageBox(_httpPort, "HTTP");
|
||||
case StartFailedException _:
|
||||
case PortInUseException _:
|
||||
break;
|
||||
default:
|
||||
Logging.Error($"主控制器未处理异常: {e}");
|
||||
break;
|
||||
}
|
||||
|
||||
if (portNotAvailable)
|
||||
{
|
||||
Logging.Error("主控制器启动失败: 端口被占用");
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting ", EncryptedProxyController.Name));
|
||||
try
|
||||
{
|
||||
result = await Task.Run(() => EncryptedProxyController.Start(server, mode));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("加密代理启动失败,未处理异常: " + e);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
// 加密代理成功启动
|
||||
UsingPorts.Add(_socks5Port);
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0: // 进程代理模式
|
||||
ModeController = new NFController();
|
||||
break;
|
||||
case 1: // TUN/TAP 黑名单代理模式
|
||||
case 2: // TUN/TAP 白名单代理模式
|
||||
ModeController = new TUNTAPController();
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
ModeController = new HTTPController();
|
||||
break;
|
||||
case 4: // Socks5 代理模式,不需要启动额外的Server
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ModeController != null)
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting ", ModeController.Name));
|
||||
try
|
||||
{
|
||||
result = await Task.Run(() => ModeController.Start(server, mode));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is DllNotFoundException || e is FileNotFoundException)
|
||||
MessageBoxX.Show(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"), owner: Global.MainForm);
|
||||
else
|
||||
Logging.Error("模式启动失败,未处理异常: " + e);
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
// 成功启动
|
||||
|
||||
switch (mode.Type) // 记录使用端口
|
||||
{
|
||||
case 0:
|
||||
UsingPorts.Add(_redirectorTCPPort);
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
UsingPorts.Add(_httpPort);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
NatTest();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Logging.Error("主控制器启动失败");
|
||||
try
|
||||
{
|
||||
await Stop();
|
||||
@@ -230,12 +83,111 @@ namespace Netch.Controllers
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool NttTested;
|
||||
private static async Task<bool> StartServer(Server server, Mode mode)
|
||||
{
|
||||
if (server.IsSocks5())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ServerController = Servers.GetUtilByTypeName(server.Type).GetController();
|
||||
|
||||
Utils.Utils.KillProcessByName(ServerController.MainFile);
|
||||
PortCheckAndShowMessageBox(Global.Settings.Socks5LocalPort, "Socks5");
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting ", ServerController.Name));
|
||||
if (await Task.Run(() => ServerController.Start(server, mode)))
|
||||
{
|
||||
UsingPorts.Add(StatusPortInfoText.Socks5Port = Global.Settings.Socks5LocalPort);
|
||||
StatusPortInfoText.ShareLan = Global.Settings.LocalAddress == "0.0.0.0";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<bool> StartMode(Server server, Mode mode)
|
||||
{
|
||||
var port = 0;
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0:
|
||||
ModeController = new NFController();
|
||||
PortCheckAndShowMessageBox(port = Global.Settings.RedirectorTCPPort, "Redirector TCP");
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
ModeController = new TUNTAPController();
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
ModeController = new HTTPController();
|
||||
PortCheckAndShowMessageBox(port = Global.Settings.HTTPLocalPort, "HTTP");
|
||||
break;
|
||||
case 4:
|
||||
return true;
|
||||
default:
|
||||
Logging.Error("未知模式类型");
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting ", ModeController.Name));
|
||||
if (await Task.Run(() => ModeController.Start(server, mode)))
|
||||
{
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 3:
|
||||
case 5:
|
||||
StatusPortInfoText.HttpPort = port;
|
||||
break;
|
||||
}
|
||||
|
||||
UsingPorts.Add(port);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public static async Task Stop()
|
||||
{
|
||||
UsingPorts.Clear();
|
||||
|
||||
_ = Task.Run(() => NTTController.Stop());
|
||||
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Run(() => ServerController?.Stop()),
|
||||
Task.Run(() => ModeController?.Stop()),
|
||||
};
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查端口是否被占用,
|
||||
/// 被占用则弹窗提示, 确认后抛出异常
|
||||
/// </summary>
|
||||
/// <param name="port">检查的端口</param>
|
||||
/// <param name="portName">端口用途名称</param>
|
||||
/// <param name="portType"></param>
|
||||
/// <exception cref="PortInUseException"></exception>
|
||||
private static void PortCheckAndShowMessageBox(int port, string portName, PortType portType = PortType.Both)
|
||||
{
|
||||
if (PortInUse(port, portType))
|
||||
{
|
||||
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", $"{portName} ({port})"));
|
||||
throw new PortInUseException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 NAT
|
||||
@@ -247,70 +199,22 @@ namespace Netch.Controllers
|
||||
{
|
||||
Global.MainForm.NatTypeStatusText(i18N.Translate("Starting NatTester"));
|
||||
// Thread.Sleep(1000);
|
||||
var (nttResult, natType, localEnd, publicEnd) = NTTController.Start();
|
||||
var (result, localEnd, publicEnd) = NTTController.Start();
|
||||
|
||||
if (nttResult)
|
||||
if (!string.IsNullOrEmpty(publicEnd))
|
||||
{
|
||||
var country = Utils.Utils.GetCityCode(publicEnd);
|
||||
Global.MainForm.NatTypeStatusText(natType, country);
|
||||
Global.MainForm.NatTypeStatusText(result, country);
|
||||
}
|
||||
else
|
||||
Global.MainForm.NatTypeStatusText(natType);
|
||||
Global.MainForm.NatTypeStatusText(result ?? "Error");
|
||||
|
||||
NttTested = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public static async Task Stop()
|
||||
{
|
||||
_httpPort = _socks5Port = _redirectorTCPPort = 0;
|
||||
_localAddress = null;
|
||||
_savedMode = null;
|
||||
_savedServer = null;
|
||||
UsingPorts.Clear();
|
||||
|
||||
var tasks = new Task[]
|
||||
{
|
||||
Task.Run(() => EncryptedProxyController?.Stop()),
|
||||
Task.Run(() => ModeController?.Stop()),
|
||||
Task.Run(() => NTTController.Stop())
|
||||
};
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public static void KillProcessByName(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var p in Process.GetProcessesByName(name))
|
||||
if (p.MainModule != null && p.MainModule.FileName.StartsWith(Global.NetchDir))
|
||||
p.Kill();
|
||||
}
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Logging.Error($"结束进程 {name} 错误:" + e.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="portName"></param>
|
||||
/// <param name="portType"></param>
|
||||
/// <returns>端口是否被占用</returns>
|
||||
private static bool PortCheckAndShowMessageBox(int port, string portName, PortType portType = PortType.Both)
|
||||
{
|
||||
if (!PortHelper.PortInUse(port, portType)) return false;
|
||||
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
|
||||
return true;
|
||||
}
|
||||
public class StartFailedException : Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,15 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Models;
|
||||
using Netch.ServerEx.Socks5;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class HTTPController : ModeController
|
||||
{
|
||||
public override bool TestNatRequired { get; } = false;
|
||||
|
||||
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.*";
|
||||
|
||||
/// <summary>
|
||||
@@ -28,24 +31,25 @@ namespace Netch.Controllers
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="s">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public override bool Start(Server server, Mode mode)
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
RecordPrevious();
|
||||
|
||||
try
|
||||
{
|
||||
if (server.Type == "Socks5")
|
||||
if (s.IsSocks5())
|
||||
{
|
||||
var server = (Socks5) s;
|
||||
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password)) return false;
|
||||
|
||||
pPrivoxyController.Start(server, mode);
|
||||
pPrivoxyController.Start(s, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrivoxyController.Start(server, mode);
|
||||
pPrivoxyController.Start(s, mode);
|
||||
}
|
||||
|
||||
if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
@@ -13,11 +11,13 @@ namespace Netch.Controllers
|
||||
{
|
||||
public class NFController : ModeController
|
||||
{
|
||||
public override bool TestNatRequired { get; } = true;
|
||||
|
||||
private static readonly ServiceController NFService = new ServiceController("netfilter2");
|
||||
|
||||
private static readonly string BinDriver = string.Empty;
|
||||
private static readonly string SystemDriver = $"{Environment.SystemDirectory}\\drivers\\netfilter2.sys";
|
||||
private static string[] _sysDns = { };
|
||||
private static string _sysDns;
|
||||
|
||||
static NFController()
|
||||
{
|
||||
@@ -45,19 +45,16 @@ namespace Netch.Controllers
|
||||
public NFController()
|
||||
{
|
||||
Name = "Redirector";
|
||||
MainFile = "Redirector.exe";
|
||||
StartedKeywords.Add("Started");
|
||||
StoppedKeywords.AddRange(new[] {"Failed", "Unable"});
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
Logging.Info("内置驱动版本: " + DriverVersion(BinDriver));
|
||||
if (DriverVersion(SystemDriver) != DriverVersion(BinDriver))
|
||||
Logging.Info("内置驱动版本: " + Utils.Utils.FileVersion(BinDriver));
|
||||
if (Utils.Utils.FileVersion(SystemDriver) != Utils.Utils.FileVersion(BinDriver))
|
||||
{
|
||||
if (File.Exists(SystemDriver))
|
||||
{
|
||||
Logging.Info("系统驱动版本: " + DriverVersion(SystemDriver));
|
||||
Logging.Info("系统驱动版本: " + Utils.Utils.FileVersion(SystemDriver));
|
||||
Logging.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
}
|
||||
@@ -66,93 +63,108 @@ namespace Netch.Controllers
|
||||
return false;
|
||||
}
|
||||
|
||||
var processList = "";
|
||||
foreach (var proc in mode.Rule)
|
||||
processList += proc + ",";
|
||||
processList += "NTT.exe";
|
||||
|
||||
var argument = new StringBuilder();
|
||||
if (server.Type != "Socks5")
|
||||
aio_dial((int) NameList.TYPE_CLRNAME, "");
|
||||
foreach (var rule in mode.Rule)
|
||||
{
|
||||
argument.Append($"-r 127.0.0.1:{Global.Settings.Socks5LocalPort} -p \"{processList}\"");
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, rule);
|
||||
}
|
||||
|
||||
else
|
||||
aio_dial((int) NameList.TYPE_ADDNAME, "NTT.exe");
|
||||
|
||||
if (s.IsSocks5())
|
||||
{
|
||||
var result = DNS.Lookup(server.Hostname);
|
||||
var result = DNS.Lookup(s.Hostname);
|
||||
if (result == null)
|
||||
{
|
||||
Logging.Info("无法解析服务器 IP 地址");
|
||||
return false;
|
||||
}
|
||||
|
||||
argument.Append($"-r {result}:{server.Port} -p \"{processList}\"");
|
||||
if (!string.IsNullOrWhiteSpace(server.Username) && !string.IsNullOrWhiteSpace(server.Password))
|
||||
argument.Append($" -username \"{server.Username}\" -password \"{server.Password}\"");
|
||||
aio_dial((int) NameList.TYPE_TCPHOST, $"{result}:{s.Port}");
|
||||
aio_dial((int) NameList.TYPE_UDPHOST, $"{result}:{s.Port}");
|
||||
}
|
||||
|
||||
argument.Append($" -t {Global.Settings.RedirectorTCPPort}");
|
||||
|
||||
for (var i = 0; i < 2; i++)
|
||||
else
|
||||
{
|
||||
State = State.Starting;
|
||||
if (!StartInstanceAuto(argument.ToString())) continue;
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
{
|
||||
//备份并替换系统DNS
|
||||
_sysDns = DNS.getSystemDns();
|
||||
string[] dns = {"1.1.1.1", "8.8.8.8"};
|
||||
DNS.SetDNS(dns);
|
||||
}
|
||||
|
||||
return true;
|
||||
aio_dial((int) NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
aio_dial((int) NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Settings.Socks5LocalPort}");
|
||||
}
|
||||
|
||||
return false;
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
{
|
||||
// 备份并替换系统 DNS
|
||||
_sysDns = DNS.OutboundDNS;
|
||||
DNS.OutboundDNS = "1.1.1.1,8.8.8.8";
|
||||
}
|
||||
|
||||
return aio_init();
|
||||
}
|
||||
|
||||
private bool RestartService()
|
||||
public override void Stop()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
//恢复系统DNS
|
||||
DNS.OutboundDNS = _sysDns;
|
||||
});
|
||||
|
||||
aio_free();
|
||||
}
|
||||
|
||||
#region NativeMethods
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_dial(int name, [MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_init();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_free();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong aio_getUP();
|
||||
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong aio_getDL();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
|
||||
/// <summary>
|
||||
/// 安装 NF 驱动
|
||||
/// </summary>
|
||||
/// <returns>驱动是否安装成功</returns>
|
||||
public static bool InstallDriver()
|
||||
{
|
||||
Logging.Info("安装 NF 驱动");
|
||||
try
|
||||
{
|
||||
switch (NFService.Status)
|
||||
{
|
||||
// 启动驱动服务
|
||||
case ServiceControllerStatus.Running:
|
||||
// 防止其他程序占用 重置 NF 百万连接数限制
|
||||
NFService.Stop();
|
||||
NFService.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting netfilter2 Service"));
|
||||
NFService.Start();
|
||||
break;
|
||||
case ServiceControllerStatus.Stopped:
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting netfilter2 Service"));
|
||||
NFService.Start();
|
||||
break;
|
||||
}
|
||||
File.Copy(BinDriver, SystemDriver);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("启动驱动服务失败:\n" + e);
|
||||
Logging.Error("驱动复制失败\n" + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result != NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Logging.Error($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("注册驱动成功");
|
||||
Global.MainForm.StatusText(i18N.Translate("Register driver"));
|
||||
// 注册驱动文件
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result == NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Logging.Info("驱动安装成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string DriverVersion(string file)
|
||||
{
|
||||
return File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载 NF 驱动
|
||||
/// </summary>
|
||||
@@ -181,48 +193,6 @@ namespace Netch.Controllers
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装 NF 驱动
|
||||
/// </summary>
|
||||
/// <returns>驱动是否安装成功</returns>
|
||||
public static bool InstallDriver()
|
||||
{
|
||||
Logging.Info("安装 NF 驱动");
|
||||
try
|
||||
{
|
||||
File.Copy(BinDriver, SystemDriver);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error("驱动复制失败\n" + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Register driver"));
|
||||
// 注册驱动文件
|
||||
var result = NFAPI.nf_registerDriver("netfilter2");
|
||||
if (result == NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Logging.Info($"驱动安装成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error($"注册驱动失败,返回值:{result}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (Global.Settings.ModifySystemDNS)
|
||||
//恢复系统DNS
|
||||
DNS.SetDNS(_sysDns);
|
||||
});
|
||||
StopInstance();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,21 +5,22 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Properties;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class TUNTAPController : ModeController
|
||||
{
|
||||
public override bool TestNatRequired { get; } = true;
|
||||
|
||||
// ByPassLan IP
|
||||
private readonly List<string> _bypassLanIPs = new List<string> {"10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16"};
|
||||
private readonly List<string> _bypassLanIPs = new List<string>
|
||||
{"10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16"};
|
||||
|
||||
private Mode _savedMode = new Mode();
|
||||
private Server _savedServer = new Server();
|
||||
@@ -57,7 +58,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
// 搜索出口
|
||||
return SearchAdapters();
|
||||
return SearchTapAdapter();
|
||||
}
|
||||
|
||||
private readonly List<IPNetwork> _directIPs = new List<IPNetwork>();
|
||||
@@ -76,7 +77,8 @@ namespace Netch.Controllers
|
||||
_directIPs.AddRange(Global.Settings.BypassIPs.Select(IPNetwork.Parse));
|
||||
|
||||
Logging.Info("绕行 → 服务器 IP");
|
||||
_directIPs.AddRange(_serverAddresses.Where(address => !IPAddress.IsLoopback(address)).Select(address => IPNetwork.Parse(address.ToString(), 32)));
|
||||
_directIPs.AddRange(_serverAddresses.Where(address => !IPAddress.IsLoopback(address))
|
||||
.Select(address => IPNetwork.Parse(address.ToString(), 32)));
|
||||
|
||||
Logging.Info("绕行 → 局域网 IP");
|
||||
_directIPs.AddRange(_bypassLanIPs.Select(IPNetwork.Parse));
|
||||
@@ -122,7 +124,9 @@ namespace Netch.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_proxyIPs.AddRange(new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => IPNetwork.Parse(ip, 32)));
|
||||
_proxyIPs.AddRange(
|
||||
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip =>
|
||||
IPNetwork.Parse(ip, 32)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +182,7 @@ namespace Netch.Controllers
|
||||
/// <summary>
|
||||
/// 清除绕行规则
|
||||
/// </summary>
|
||||
private bool ClearBypass()
|
||||
private bool ClearRouteTable()
|
||||
{
|
||||
switch (_savedMode.Type)
|
||||
{
|
||||
@@ -196,10 +200,10 @@ namespace Netch.Controllers
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
_savedMode = mode;
|
||||
_savedServer = server;
|
||||
_savedServer = s;
|
||||
|
||||
if (!Configure()) return false;
|
||||
|
||||
@@ -208,30 +212,36 @@ namespace Netch.Controllers
|
||||
var adapterName = TUNTAP.GetName(Global.TUNTAP.ComponentID);
|
||||
|
||||
string dns;
|
||||
//V2ray使用Unbound本地DNS会导致查询异常缓慢故此V2ray不启动unbound而是使用自定义DNS
|
||||
//if (Global.Settings.TUNTAP.UseCustomDNS || server.Type.Equals("VMess"))
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
dns = Global.Settings.TUNTAP.DNS.Aggregate(string.Empty, (current, value) => current + (value + ',')).Trim();
|
||||
dns = dns.Substring(0, dns.Length - 1);
|
||||
if (Global.Settings.TUNTAP.DNS.Any())
|
||||
{
|
||||
dns = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.Settings.TUNTAP.DNS.Add("1.1.1.1");
|
||||
dns = "1.1.1.1";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pDNSController.Start();
|
||||
var _ = pDNSController.Start();
|
||||
dns = "127.0.0.1";
|
||||
}
|
||||
|
||||
if (Global.Settings.TUNTAP.UseFakeDNS) dns += " -fakeDns";
|
||||
|
||||
var argument = new StringBuilder();
|
||||
if (server.Type == "Socks5")
|
||||
argument.Append($"-proxyServer {server.Hostname}:{server.Port} ");
|
||||
if (s.IsSocks5())
|
||||
argument.Append($"-proxyServer {s.Hostname}:{s.Port} ");
|
||||
else
|
||||
argument.Append($"-proxyServer 127.0.0.1:{Global.Settings.Socks5LocalPort} ");
|
||||
|
||||
argument.Append($"-tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {dns} -tunName \"{adapterName}\"");
|
||||
argument.Append(
|
||||
$"-tunAddr {Global.Settings.TUNTAP.Address} -tunMask {Global.Settings.TUNTAP.Netmask} -tunGw {Global.Settings.TUNTAP.Gateway} -tunDns {dns} -tunName \"{adapterName}\" ");
|
||||
|
||||
if (Global.Settings.TUNTAP.UseFakeDNS && Global.Flags.SupportFakeDns)
|
||||
argument.Append("-fakeDns ");
|
||||
|
||||
State = State.Starting;
|
||||
return StartInstanceAuto(argument.ToString(), ProcessPriorityClass.RealTime);
|
||||
}
|
||||
|
||||
@@ -243,33 +253,59 @@ namespace Netch.Controllers
|
||||
var tasks = new[]
|
||||
{
|
||||
Task.Factory.StartNew(StopInstance),
|
||||
Task.Factory.StartNew(ClearBypass),
|
||||
Task.Factory.StartNew(ClearRouteTable),
|
||||
Task.Factory.StartNew(pDNSController.Stop)
|
||||
};
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
public bool TestFakeDNS()
|
||||
{
|
||||
var exited = false;
|
||||
var helpStr = new StringBuilder();
|
||||
try
|
||||
{
|
||||
void OnOutputDataReceived(object sender,DataReceivedEventArgs e)
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
exited = true;
|
||||
return;
|
||||
}
|
||||
helpStr.Append(e.Data);
|
||||
}
|
||||
InitInstance("-h");
|
||||
// Instance.OutputDataReceived += OnOutputDataReceived;
|
||||
Instance.ErrorDataReceived += OnOutputDataReceived;
|
||||
Instance.Start();
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
while (!exited)
|
||||
{
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
return helpStr.ToString().Contains("-fakeDns");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索出口和TUNTAP适配器
|
||||
/// </summary>
|
||||
private static bool SearchAdapters()
|
||||
public static bool SearchTapAdapter()
|
||||
{
|
||||
// 寻找出口适配器
|
||||
if (Win32Native.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0)
|
||||
{
|
||||
Logging.Error("GetBestRoute 搜索失败(找不到出口适配器)");
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.Adapter.Index = pRoute.dwForwardIfIndex;
|
||||
|
||||
// 搜索 TUN/TAP 适配器的索引
|
||||
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID = TUNTAP.GetComponentID()))
|
||||
{
|
||||
Logging.Info("找不到 TAP 适配器");
|
||||
if (MessageBoxX.Show(i18N.Translate("TUN/TAP driver is not detected. Is it installed now?"), confirm: true) == DialogResult.OK)
|
||||
if (MessageBoxX.Show(i18N.Translate("TUN/TAP driver is not detected. Is it installed now?"),
|
||||
confirm: true) == DialogResult.OK)
|
||||
{
|
||||
Configuration.addtap();
|
||||
TUNTAP.addtap();
|
||||
// 给点时间,不然立马安装完毕就查找适配器可能会导致找不到适配器ID
|
||||
Thread.Sleep(1000);
|
||||
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID = TUNTAP.GetComponentID()))
|
||||
@@ -285,42 +321,14 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
// 根据 IP Index 寻找 出口适配器
|
||||
var errorAdaptersId = new List<string>();
|
||||
try
|
||||
{
|
||||
var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _.GetIPProperties().GetIPv4Properties().Index == Global.Adapter.Index;
|
||||
}
|
||||
catch (NetworkInformationException)
|
||||
{
|
||||
errorAdaptersId.Add(_.Id);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Global.Adapter.Address = adapter.GetIPProperties().UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork).Address;
|
||||
Global.Adapter.Gateway = new IPAddress(pRoute.dwForwardNextHop);
|
||||
Logging.Info($"出口 IPv4 地址:{Global.Adapter.Address}");
|
||||
Logging.Info($"出口 网关 地址:{Global.Adapter.Gateway}");
|
||||
Logging.Info($"出口适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.Adapter.Index}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"找不到 IP Index 为 {Global.Adapter.Index} 的出口适配器: {e.Message}");
|
||||
PrintAdapters();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 根据 ComponentID 寻找 Tap适配器
|
||||
try
|
||||
{
|
||||
var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ => _.Id == Global.TUNTAP.ComponentID);
|
||||
Global.TUNTAP.Adapter = adapter;
|
||||
Global.TUNTAP.Index = adapter.GetIPProperties().GetIPv4Properties().Index;
|
||||
Logging.Info($"TAP 适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.TUNTAP.Index}");
|
||||
Logging.Info(
|
||||
$"TAP 适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.TUNTAP.Index}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -331,18 +339,10 @@ namespace Netch.Controllers
|
||||
_ => $"Tap 适配器其他异常: {e}"
|
||||
};
|
||||
Logging.Error(msg);
|
||||
PrintAdapters();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
void PrintAdapters()
|
||||
{
|
||||
Logging.Info("所有适配器:\n" +
|
||||
NetworkInterface.GetAllNetworkInterfaces().Aggregate(string.Empty, (current, adapter)
|
||||
=> current + $"{ /*如果加了 ’*‘ 代表遍历中出现异常的适配器 */(errorAdaptersId.Contains(adapter.Id) ? "*" : "")}{adapter.Name} {adapter.Id} {adapter.Description}{Global.EOF}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -358,7 +358,8 @@ namespace Netch.Controllers
|
||||
Delete
|
||||
}
|
||||
|
||||
private static void RouteAction(Action action, IEnumerable<IPNetwork> ipNetworks, RouteType routeType, int metric = 0)
|
||||
private static void RouteAction(Action action, IEnumerable<IPNetwork> ipNetworks, RouteType routeType,
|
||||
int metric = 0)
|
||||
{
|
||||
foreach (var address in ipNetworks)
|
||||
{
|
||||
@@ -378,8 +379,8 @@ namespace Netch.Controllers
|
||||
switch (routeType)
|
||||
{
|
||||
case RouteType.Gateway:
|
||||
gateway = Global.Adapter.Gateway.ToString();
|
||||
index = Global.Adapter.Index;
|
||||
gateway = Global.Outbound.Gateway.ToString();
|
||||
index = Global.Outbound.Index;
|
||||
break;
|
||||
case RouteType.TUNTAP:
|
||||
gateway = Global.Settings.TUNTAP.Gateway;
|
||||
@@ -391,8 +392,10 @@ namespace Netch.Controllers
|
||||
|
||||
var result = action switch
|
||||
{
|
||||
Action.Create => NativeMethods.CreateRoute(ipNetwork.Network.ToString(), ipNetwork.Cidr, gateway, index, metric),
|
||||
Action.Delete => NativeMethods.DeleteRoute(ipNetwork.Network.ToString(), ipNetwork.Cidr, gateway, index, metric),
|
||||
Action.Create => NativeMethods.CreateRoute(ipNetwork.Network.ToString(), ipNetwork.Cidr, gateway, index,
|
||||
metric),
|
||||
Action.Delete => NativeMethods.DeleteRoute(ipNetwork.Network.ToString(), ipNetwork.Cidr, gateway, index,
|
||||
metric),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(action), action, null)
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
@@ -10,8 +9,8 @@ namespace Netch.Controllers
|
||||
{
|
||||
private string _localEnd;
|
||||
private string _publicEnd;
|
||||
private string _natType;
|
||||
private bool _nttResult;
|
||||
private string _result;
|
||||
private string _bindingTest;
|
||||
|
||||
public NTTController()
|
||||
{
|
||||
@@ -23,10 +22,9 @@ namespace Netch.Controllers
|
||||
/// 启动 NatTypeTester
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (bool, string, string, string) Start()
|
||||
public (string, string, string) Start()
|
||||
{
|
||||
_nttResult = false;
|
||||
_natType = _localEnd = _publicEnd = null;
|
||||
_result = _localEnd = _publicEnd = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -37,7 +35,9 @@ namespace Netch.Controllers
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
Instance.WaitForExit();
|
||||
return (_nttResult, _natType, _localEnd, _publicEnd);
|
||||
if (_bindingTest == "Fail")
|
||||
_result = "UdpBlocked";
|
||||
return (_result, _localEnd, _publicEnd);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace Netch.Controllers
|
||||
// ignored
|
||||
}
|
||||
|
||||
return (false, null, null, null);
|
||||
return (null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,10 +68,12 @@ namespace Netch.Controllers
|
||||
switch (key)
|
||||
{
|
||||
case "Other address is":
|
||||
case "Binding test":
|
||||
case "Nat mapping behavior":
|
||||
case "Nat filtering behavior":
|
||||
break;
|
||||
case "Binding test":
|
||||
_bindingTest = value;
|
||||
break;
|
||||
case "Local address":
|
||||
_localEnd = value;
|
||||
break;
|
||||
@@ -79,11 +81,10 @@ namespace Netch.Controllers
|
||||
_publicEnd = value;
|
||||
break;
|
||||
case "result":
|
||||
_natType = value;
|
||||
_nttResult = true;
|
||||
_result = value;
|
||||
break;
|
||||
default:
|
||||
_natType = str.Last();
|
||||
_result = str.Last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,11 @@ namespace Netch.Controllers
|
||||
|
||||
public bool Start(Server server, Mode mode)
|
||||
{
|
||||
var isSocks5 = server.Type == "Socks5";
|
||||
var socks5Port = isSocks5 ? server.Port : Global.Settings.Socks5LocalPort;
|
||||
var text = File.ReadAllText("bin\\default.conf")
|
||||
.Replace("_BIND_PORT_", Global.Settings.HTTPLocalPort.ToString())
|
||||
.Replace("_DEST_PORT_", socks5Port.ToString())
|
||||
.Replace("_DEST_PORT_", (server.IsSocks5() ? server.Port : Global.Settings.Socks5LocalPort).ToString())
|
||||
.Replace("0.0.0.0", Global.Settings.LocalAddress);
|
||||
if (isSocks5)
|
||||
if (server.IsSocks5())
|
||||
text = text.Replace("/ 127.0.0.1", $"/ {server.Hostname}");
|
||||
File.WriteAllText("data\\privoxy.conf", text);
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using Netch.Models.GitHubRelease;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class UpdateChecker
|
||||
@@ -15,7 +14,11 @@ namespace Netch.Controllers
|
||||
|
||||
public const string Name = @"Netch";
|
||||
public const string Copyright = @"Copyright © 2019 - 2020";
|
||||
public const string Version = @"1.5.1";
|
||||
|
||||
public const string AssemblyVersion = @"1.6.0";
|
||||
private const string Suffix = @"Beta1";
|
||||
|
||||
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";
|
||||
|
||||
public string LatestVersionNumber;
|
||||
public string LatestVersionUrl;
|
||||
@@ -42,7 +45,7 @@ namespace Netch.Controllers
|
||||
Logging.Info($"Github 最新发布版本: {latestRelease.tag_name}");
|
||||
if (VersionUtil.CompareVersion(latestRelease.tag_name, Version) > 0)
|
||||
{
|
||||
Logging.Info($"发现新版本");
|
||||
Logging.Info("发现新版本");
|
||||
NewVersionFound?.Invoke(this, new EventArgs());
|
||||
}
|
||||
else
|
||||
|
||||
@@ -14,9 +14,7 @@ namespace Netch.Forms
|
||||
|
||||
private void AboutForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = i18N.Translate(Text);
|
||||
ChannelLabel.Text = i18N.Translate(ChannelLabel.Text);
|
||||
SponsorGroupBox.Text = i18N.Translate(SponsorGroupBox.Text);
|
||||
i18N.TranslateForm(this);
|
||||
}
|
||||
|
||||
private void NetchPictureBox_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -14,10 +14,7 @@ namespace Netch.Forms
|
||||
|
||||
private void GlobalBypassIPForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = i18N.Translate(Text);
|
||||
AddButton.Text = i18N.Translate(AddButton.Text);
|
||||
DeleteButton.Text = i18N.Translate(DeleteButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
IPListBox.Items.AddRange(Global.Settings.BypassIPs.ToArray());
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
@@ -24,13 +22,13 @@ namespace Netch.Forms
|
||||
if (State == State.Waiting || State == State.Stopped)
|
||||
{
|
||||
// 服务器、模式 需选择
|
||||
if (ServerComboBox.SelectedIndex == -1)
|
||||
if (!(ServerComboBox.SelectedItem is Server server))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a server first"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ModeComboBox.SelectedIndex == -1)
|
||||
if (!(ModeComboBox.SelectedItem is Models.Mode mode))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
|
||||
return;
|
||||
@@ -41,9 +39,6 @@ namespace Netch.Forms
|
||||
|
||||
State = State.Starting;
|
||||
|
||||
var server = ServerComboBox.SelectedItem as Models.Server;
|
||||
var mode = ModeComboBox.SelectedItem as Models.Mode;
|
||||
|
||||
if (await MainController.Start(server, mode))
|
||||
{
|
||||
State = State.Started;
|
||||
|
||||
117
Netch/Forms/MainForm.Designer.cs
generated
117
Netch/Forms/MainForm.Designer.cs
generated
@@ -1,6 +1,4 @@
|
||||
using Netch.Override;
|
||||
|
||||
namespace Netch.Forms
|
||||
namespace Netch.Forms
|
||||
{
|
||||
partial class MainForm
|
||||
{
|
||||
@@ -35,13 +33,7 @@ namespace Netch.Forms
|
||||
this.MenuStrip = new System.Windows.Forms.MenuStrip();
|
||||
this.ServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ImportServersFromClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AddSocks5ServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AddShadowsocksServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AddShadowsocksRServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AddVMessServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AddTrojanServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.HelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CreateProcessModeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ReloadModesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SubscribeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -54,11 +46,13 @@ namespace Netch.Forms
|
||||
this.updateACLWithProxyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.UninstallServiceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.reinstallTapDriverToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.HelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CheckForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AboutToolStripButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.VersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
this.NewVersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
this.fAQToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AboutToolStripButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.NewVersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
this.VersionLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.configLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.ProfileLabel = new System.Windows.Forms.Label();
|
||||
@@ -130,12 +124,7 @@ namespace Netch.Forms
|
||||
// ServerToolStripMenuItem
|
||||
//
|
||||
this.ServerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ImportServersFromClipboardToolStripMenuItem,
|
||||
this.AddSocks5ServerToolStripMenuItem,
|
||||
this.AddShadowsocksServerToolStripMenuItem,
|
||||
this.AddShadowsocksRServerToolStripMenuItem,
|
||||
this.AddVMessServerToolStripMenuItem,
|
||||
this.AddTrojanServerToolStripMenuItem});
|
||||
this.ImportServersFromClipboardToolStripMenuItem});
|
||||
this.ServerToolStripMenuItem.Margin = new System.Windows.Forms.Padding(3, 0, 0, 1);
|
||||
this.ServerToolStripMenuItem.Name = "ServerToolStripMenuItem";
|
||||
this.ServerToolStripMenuItem.Size = new System.Drawing.Size(57, 21);
|
||||
@@ -148,41 +137,6 @@ namespace Netch.Forms
|
||||
this.ImportServersFromClipboardToolStripMenuItem.Text = "Import Servers From Clipboard";
|
||||
this.ImportServersFromClipboardToolStripMenuItem.Click += new System.EventHandler(this.ImportServersFromClipboardToolStripMenuItem_Click);
|
||||
//
|
||||
// AddSocks5ServerToolStripMenuItem
|
||||
//
|
||||
this.AddSocks5ServerToolStripMenuItem.Name = "AddSocks5ServerToolStripMenuItem";
|
||||
this.AddSocks5ServerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.AddSocks5ServerToolStripMenuItem.Text = "Add [Socks5] Server";
|
||||
this.AddSocks5ServerToolStripMenuItem.Click += new System.EventHandler(this.AddServerToolStripMenuItem_Click);
|
||||
//
|
||||
// AddShadowsocksServerToolStripMenuItem
|
||||
//
|
||||
this.AddShadowsocksServerToolStripMenuItem.Name = "AddShadowsocksServerToolStripMenuItem";
|
||||
this.AddShadowsocksServerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.AddShadowsocksServerToolStripMenuItem.Text = "Add [Shadowsocks] Server";
|
||||
this.AddShadowsocksServerToolStripMenuItem.Click += new System.EventHandler(this.AddServerToolStripMenuItem_Click);
|
||||
//
|
||||
// AddShadowsocksRServerToolStripMenuItem
|
||||
//
|
||||
this.AddShadowsocksRServerToolStripMenuItem.Name = "AddShadowsocksRServerToolStripMenuItem";
|
||||
this.AddShadowsocksRServerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.AddShadowsocksRServerToolStripMenuItem.Text = "Add [ShadowsocksR] Server";
|
||||
this.AddShadowsocksRServerToolStripMenuItem.Click += new System.EventHandler(this.AddServerToolStripMenuItem_Click);
|
||||
//
|
||||
// AddVMessServerToolStripMenuItem
|
||||
//
|
||||
this.AddVMessServerToolStripMenuItem.Name = "AddVMessServerToolStripMenuItem";
|
||||
this.AddVMessServerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.AddVMessServerToolStripMenuItem.Text = "Add [VMess] Server";
|
||||
this.AddVMessServerToolStripMenuItem.Click += new System.EventHandler(this.AddServerToolStripMenuItem_Click);
|
||||
//
|
||||
// AddTrojanServerToolStripMenuItem
|
||||
//
|
||||
this.AddTrojanServerToolStripMenuItem.Name = "AddTrojanServerToolStripMenuItem";
|
||||
this.AddTrojanServerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.AddTrojanServerToolStripMenuItem.Text = "Add [Trojan] Server";
|
||||
this.AddTrojanServerToolStripMenuItem.Click += new System.EventHandler(this.AddServerToolStripMenuItem_Click);
|
||||
//
|
||||
// ModeToolStripMenuItem
|
||||
//
|
||||
this.ModeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@@ -193,15 +147,6 @@ namespace Netch.Forms
|
||||
this.ModeToolStripMenuItem.Size = new System.Drawing.Size(55, 21);
|
||||
this.ModeToolStripMenuItem.Text = "Mode";
|
||||
//
|
||||
// HelpToolStripMenuItem
|
||||
//
|
||||
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.CheckForUpdatesToolStripMenuItem});
|
||||
this.HelpToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.HelpToolStripMenuItem.Name = "HelpToolStripMenuItem";
|
||||
this.HelpToolStripMenuItem.Size = new System.Drawing.Size(55, 21);
|
||||
this.HelpToolStripMenuItem.Text = "Help";
|
||||
//
|
||||
// CreateProcessModeToolStripMenuItem
|
||||
//
|
||||
this.CreateProcessModeToolStripMenuItem.Name = "CreateProcessModeToolStripMenuItem";
|
||||
@@ -296,13 +241,37 @@ namespace Netch.Forms
|
||||
this.reinstallTapDriverToolStripMenuItem.Text = "Reinstall TUN/TAP driver";
|
||||
this.reinstallTapDriverToolStripMenuItem.Click += new System.EventHandler(this.reinstallTapDriverToolStripMenuItem_Click);
|
||||
//
|
||||
// HelpToolStripMenuItem
|
||||
//
|
||||
this.HelpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.CheckForUpdatesToolStripMenuItem,
|
||||
this.fAQToolStripMenuItem});
|
||||
this.HelpToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
|
||||
this.HelpToolStripMenuItem.Name = "HelpToolStripMenuItem";
|
||||
this.HelpToolStripMenuItem.Size = new System.Drawing.Size(47, 21);
|
||||
this.HelpToolStripMenuItem.Text = "Help";
|
||||
//
|
||||
// CheckForUpdatesToolStripMenuItem
|
||||
//
|
||||
this.CheckForUpdatesToolStripMenuItem.Name = "CheckForUpdatesToolStripMenuItem";
|
||||
this.CheckForUpdatesToolStripMenuItem.Size = new System.Drawing.Size(219, 22);
|
||||
this.CheckForUpdatesToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
|
||||
this.CheckForUpdatesToolStripMenuItem.Text = "Check for updates";
|
||||
this.CheckForUpdatesToolStripMenuItem.Click += new System.EventHandler(this.CheckForUpdatesToolStripMenuItem_Click);
|
||||
//
|
||||
// fAQToolStripMenuItem
|
||||
//
|
||||
this.fAQToolStripMenuItem.Name = "fAQToolStripMenuItem";
|
||||
this.fAQToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
|
||||
this.fAQToolStripMenuItem.Text = "FAQ";
|
||||
this.fAQToolStripMenuItem.Click += new System.EventHandler(this.fAQToolStripMenuItem_Click);
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(40, 22);
|
||||
this.exitToolStripMenuItem.Text = "Exit";
|
||||
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
|
||||
//
|
||||
// AboutToolStripButton
|
||||
//
|
||||
this.AboutToolStripButton.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
|
||||
@@ -318,13 +287,13 @@ namespace Netch.Forms
|
||||
this.NewVersionLabel.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
|
||||
this.NewVersionLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
this.NewVersionLabel.ForeColor = System.Drawing.Color.Red;
|
||||
this.NewVersionLabel.LinkColor = System.Drawing.Color.Red;
|
||||
this.NewVersionLabel.IsLink = true;
|
||||
this.NewVersionLabel.Visible = false;
|
||||
this.NewVersionLabel.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline;
|
||||
this.NewVersionLabel.LinkColor = System.Drawing.Color.Red;
|
||||
this.NewVersionLabel.Name = "NewVersionLabel";
|
||||
this.NewVersionLabel.Size = new System.Drawing.Size(26, 19);
|
||||
this.NewVersionLabel.Size = new System.Drawing.Size(135, 19);
|
||||
this.NewVersionLabel.Text = "New version available";
|
||||
this.NewVersionLabel.Visible = false;
|
||||
this.NewVersionLabel.Click += new System.EventHandler(this.NewVersionLabel_Click);
|
||||
//
|
||||
// VersionLabel
|
||||
@@ -339,13 +308,6 @@ namespace Netch.Forms
|
||||
this.VersionLabel.Text = "xxx";
|
||||
this.VersionLabel.Click += new System.EventHandler(this.VersionLabel_Click);
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(40, 22);
|
||||
this.exitToolStripMenuItem.Text = "Exit";
|
||||
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
|
||||
//
|
||||
// ConfigurationGroupBox
|
||||
//
|
||||
this.ConfigurationGroupBox.Controls.Add(this.configLayoutPanel);
|
||||
@@ -596,7 +558,7 @@ namespace Netch.Forms
|
||||
// blankToolStripStatusLabel
|
||||
//
|
||||
this.blankToolStripStatusLabel.Name = "blankToolStripStatusLabel";
|
||||
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(268, 17);
|
||||
this.blankToolStripStatusLabel.Size = new System.Drawing.Size(487, 17);
|
||||
this.blankToolStripStatusLabel.Spring = true;
|
||||
//
|
||||
// NatTypeStatusLabel
|
||||
@@ -744,11 +706,6 @@ namespace Netch.Forms
|
||||
}
|
||||
|
||||
private System.Windows.Forms.ToolStripButton AboutToolStripButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddShadowsocksRServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddShadowsocksServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddSocks5ServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddTrojanServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AddVMessServerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem CleanDNSCacheToolStripMenuItem;
|
||||
private System.Windows.Forms.TableLayoutPanel configLayoutPanel;
|
||||
private System.Windows.Forms.GroupBox ConfigurationGroupBox;
|
||||
@@ -802,7 +759,9 @@ namespace Netch.Forms
|
||||
private System.Windows.Forms.ToolStripLabel VersionLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel NatTypeStatusLightLabel;
|
||||
private System.Windows.Forms.ToolStripStatusLabel blankToolStripStatusLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem fAQToolStripMenuItem;
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Forms.Server;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Trojan = Netch.Forms.Server.Trojan;
|
||||
using VMess = Netch.Forms.Server.VMess;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -31,7 +26,7 @@ namespace Netch.Forms
|
||||
var texts = Clipboard.GetText();
|
||||
if (!string.IsNullOrWhiteSpace(texts))
|
||||
{
|
||||
var result = ShareLink.Parse(texts);
|
||||
var result = ShareLink.ParseText(texts);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
@@ -52,18 +47,15 @@ namespace Netch.Forms
|
||||
|
||||
private void AddServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Form form = ((ToolStripMenuItem)sender).Name switch
|
||||
{
|
||||
"AddSocks5ServerToolStripMenuItem" => new Socks5(),
|
||||
"AddShadowsocksServerToolStripMenuItem" => new Shadowsocks(),
|
||||
"AddShadowsocksRServerToolStripMenuItem" => new ShadowsocksR(),
|
||||
"AddVMessServerToolStripMenuItem" => new VMess(),
|
||||
"AddTrojanServerToolStripMenuItem" => new Trojan(),
|
||||
_ => null
|
||||
};
|
||||
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();
|
||||
form?.ShowDialog();
|
||||
Servers.GetUtilByFullName(result).Create();
|
||||
|
||||
InitServer();
|
||||
Configuration.Save();
|
||||
Show();
|
||||
@@ -113,12 +105,11 @@ namespace Netch.Forms
|
||||
|
||||
private async void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
UpdateServersFromSubscribe();
|
||||
await UpdateServersFromSubscribe();
|
||||
}
|
||||
|
||||
public async void UpdateServersFromSubscribe()
|
||||
public async Task UpdateServersFromSubscribe()
|
||||
{
|
||||
|
||||
void DisableItems(bool v)
|
||||
{
|
||||
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ProfileGroupBox.Enabled = ControlButton.Enabled = v;
|
||||
@@ -150,7 +141,7 @@ namespace Netch.Forms
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
}
|
||||
|
||||
var serverLock = new object();
|
||||
@@ -167,20 +158,11 @@ namespace Netch.Forms
|
||||
|
||||
var str = await WebUtil.DownloadStringAsync(request);
|
||||
|
||||
try
|
||||
{
|
||||
str = ShareLink.URLSafeBase64Decode(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
lock (serverLock)
|
||||
{
|
||||
Global.Settings.Server.RemoveAll(server => server.Group == item.Remark);
|
||||
|
||||
var result = ShareLink.Parse(str);
|
||||
var result = ShareLink.ParseText(str);
|
||||
if (result != null)
|
||||
{
|
||||
foreach (var server in result)
|
||||
@@ -303,7 +285,7 @@ namespace Netch.Forms
|
||||
Type = 5
|
||||
};
|
||||
State = State.Starting;
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
}
|
||||
|
||||
var req = WebUtil.CreateRequest(Global.Settings.ACL);
|
||||
@@ -358,8 +340,8 @@ namespace Netch.Forms
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Configuration.deltapall();
|
||||
Configuration.addtap();
|
||||
TUNTAP.deltapall();
|
||||
TUNTAP.addtap();
|
||||
});
|
||||
StatusText(i18N.Translate("Reinstall TUN/TAP driver successfully"));
|
||||
}
|
||||
@@ -394,6 +376,11 @@ namespace Netch.Forms
|
||||
Show();
|
||||
}
|
||||
|
||||
private void fAQToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Utils.Utils.Open($"https://netch.org/#/docs/zh-CN/faq");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,9 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Utils;
|
||||
using Process = System.Diagnostics.Process;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
@@ -31,40 +27,35 @@ namespace Netch.Forms
|
||||
{
|
||||
_updater.NewVersionFound += (o, args) =>
|
||||
{
|
||||
if (_updater.LatestVersionDownloadUrl.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
NotifyTip($"{i18N.Translate(@"New version available", ": ")}{_updater.LatestVersionNumber}");
|
||||
NewVersionLabel.Visible = true;
|
||||
}
|
||||
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.LatestVersionDownloadUrl.Contains("Netch"))
|
||||
{
|
||||
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 fileName = $"Netch{_updater.LatestVersionNumber}.zip";
|
||||
var fileName = Path.GetFileName(new Uri(_updater.LatestVersionDownloadUrl).LocalPath);
|
||||
fileName = fileName.Insert(fileName.LastIndexOf('.'), _updater.LatestVersionNumber);
|
||||
var fileFullPath = Path.Combine(Global.NetchDir, "data", fileName);
|
||||
var updateFileValid = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(fileFullPath))
|
||||
if (!File.Exists(fileFullPath))
|
||||
{
|
||||
if (!(updateFileValid = Utils.Utils.IsZipValid(fileFullPath)))
|
||||
{
|
||||
File.Delete(fileFullPath);
|
||||
}
|
||||
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(_updater.LatestVersionDownloadUrl), fileFullPath);
|
||||
}
|
||||
|
||||
if (!File.Exists(fileFullPath))
|
||||
await WebUtil.DownloadFileAsync(WebUtil.CreateRequest(_updater.LatestVersionDownloadUrl), fileFullPath);
|
||||
if (updateFileValid || Utils.Utils.IsZipValid(fileFullPath))
|
||||
RunUpdater();
|
||||
else
|
||||
throw new InvalidDataException($"{fileFullPath} invalid");
|
||||
RunUpdater();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
@@ -83,48 +83,34 @@ namespace Netch.Forms
|
||||
}
|
||||
}
|
||||
|
||||
private string LoadProfile(int index)
|
||||
private void LoadProfile(int index)
|
||||
{
|
||||
var p = Global.Settings.Profiles[index];
|
||||
ProfileNameText.Text = p.ModeRemark;
|
||||
|
||||
if (p.IsDummy)
|
||||
throw new Exception("Profile not found.");
|
||||
|
||||
var result = false;
|
||||
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));
|
||||
|
||||
foreach (Models.Server server in ServerComboBox.Items)
|
||||
if (server == null)
|
||||
{
|
||||
if (server.Remark.Equals(p.ServerRemark))
|
||||
{
|
||||
ServerComboBox.SelectedItem = server;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
throw new Exception("Server not found.");
|
||||
|
||||
result = false;
|
||||
foreach (Models.Mode mode in ModeComboBox.Items)
|
||||
{
|
||||
if (mode.Remark.Equals(p.ModeRemark))
|
||||
{
|
||||
ModeComboBox.SelectedItem = mode;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
if (mode == null)
|
||||
{
|
||||
throw new Exception("Mode not found.");
|
||||
}
|
||||
|
||||
return p.ProfileName;
|
||||
ServerComboBox.SelectedItem = server;
|
||||
ModeComboBox.SelectedItem = mode;
|
||||
}
|
||||
|
||||
private void SaveProfile(int index)
|
||||
{
|
||||
var selectedServer = (Models.Server) ServerComboBox.SelectedItem;
|
||||
var selectedServer = (Server) ServerComboBox.SelectedItem;
|
||||
var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
var name = ProfileNameText.Text;
|
||||
|
||||
@@ -168,7 +154,8 @@ namespace Netch.Forms
|
||||
|
||||
if (Global.Settings.Profiles[index].IsDummy)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("No saved profile here. Save a profile first by Ctrl+Click on the button"));
|
||||
MessageBoxX.Show(
|
||||
i18N.Translate("No saved profile here. Save a profile first by Ctrl+Click on the button"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,32 +164,29 @@ namespace Netch.Forms
|
||||
if (MessageBoxX.Show(i18N.Translate("Remove this Profile?"), confirm: true) != DialogResult.OK) return;
|
||||
RemoveProfile(index);
|
||||
ProfileButtons[index].Text = i18N.Translate("None");
|
||||
// MessageBoxX.Show(i18N.Translate("Profile Removed!"));
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProfileNameText.Text = LoadProfile(index);
|
||||
|
||||
// start the profile
|
||||
ControlFun();
|
||||
if (State == State.Stopping || State == State.Stopped)
|
||||
{
|
||||
while (State != State.Stopped)
|
||||
{
|
||||
await Task.Delay(250);
|
||||
}
|
||||
|
||||
ControlFun();
|
||||
}
|
||||
LoadProfile(index);
|
||||
}
|
||||
catch (Exception ee)
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logging.Info(ee.ToString());
|
||||
ProfileButtons[index].Text = i18N.Translate("Error");
|
||||
await Task.Delay(1200);
|
||||
ProfileButtons[index].Text = i18N.Translate("None");
|
||||
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,6 +1,5 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
@@ -68,6 +67,7 @@ namespace Netch.Forms
|
||||
|
||||
ModeComboBox.Items.Clear();
|
||||
ModeComboBox.Items.AddRange(Global.Modes.ToArray());
|
||||
ModeComboBox.Tag = null;
|
||||
SelectLastMode();
|
||||
_comboBoxInitialized = comboBoxInitialized;
|
||||
}
|
||||
@@ -154,5 +154,22 @@ namespace Netch.Forms
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAddServerToolStripMenuItems()
|
||||
{
|
||||
foreach (var serversUtil in Servers.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,8 +1,6 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Netch.Controllers;
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
@@ -14,6 +12,8 @@ namespace Netch.Forms
|
||||
|
||||
partial class MainForm
|
||||
{
|
||||
private bool IsWaiting => State == State.Waiting || State == State.Stopped;
|
||||
|
||||
private State _state = State.Waiting;
|
||||
|
||||
/// <summary>
|
||||
@@ -24,13 +24,6 @@ namespace Netch.Forms
|
||||
get => _state;
|
||||
private set
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
// TODO:使所有 State 赋值不在线程中执行然后移除此代码块
|
||||
BeginInvoke(new Action(() => { State = value; }));
|
||||
return;
|
||||
}
|
||||
|
||||
void StartDisableItems(bool enabled)
|
||||
{
|
||||
ServerComboBox.Enabled =
|
||||
@@ -69,11 +62,11 @@ namespace Netch.Forms
|
||||
ControlButton.Enabled = true;
|
||||
ControlButton.Text = i18N.Translate("Stop");
|
||||
|
||||
StatusTextAppend(MainController.PortInfo);
|
||||
StatusTextAppend(StatusPortInfoText.Value);
|
||||
|
||||
ProfileGroupBox.Enabled = true;
|
||||
|
||||
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = Bandwidth.NetTrafficAvailable;
|
||||
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = Global.Flags.IsWindows10Upper;
|
||||
break;
|
||||
case State.Stopping:
|
||||
ControlButton.Enabled = false;
|
||||
@@ -119,27 +112,9 @@ namespace Netch.Forms
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
if (country != "")
|
||||
{
|
||||
NatTypeStatusLabel.Text = String.Format("NAT{0}{1} [{2}]", i18N.Translate(": "), text, country);
|
||||
}
|
||||
else
|
||||
{
|
||||
NatTypeStatusLabel.Text = String.Format("NAT{0}{1}", i18N.Translate(": "), text);
|
||||
}
|
||||
NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} {(country != string.Empty ? $"[{country}]" : "")}";
|
||||
|
||||
if (int.TryParse(text, out int natType))
|
||||
{
|
||||
if (natType > 0 && natType < 5)
|
||||
{
|
||||
NatTypeStatusLightLabel.Visible = true;
|
||||
UpdateNatTypeLight(natType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NatTypeStatusLightLabel.Visible = false;
|
||||
}
|
||||
UpdateNatTypeLight(int.TryParse(text, out var natType) ? natType : -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -153,59 +128,37 @@ namespace Netch.Forms
|
||||
/// 更新 NAT指示灯颜色
|
||||
/// </summary>
|
||||
/// <param name="natType"></param>
|
||||
private void UpdateNatTypeLight(STUN_Client.NatType natType)
|
||||
private void UpdateNatTypeLight(int natType = -1)
|
||||
{
|
||||
Color c;
|
||||
switch (natType)
|
||||
if (natType > 0 && natType < 5)
|
||||
{
|
||||
case STUN_Client.NatType.UdpBlocked:
|
||||
case STUN_Client.NatType.SymmetricUdpFirewall:
|
||||
case STUN_Client.NatType.Symmetric:
|
||||
c = Color.Red;
|
||||
break;
|
||||
case STUN_Client.NatType.RestrictedCone:
|
||||
case STUN_Client.NatType.PortRestrictedCone:
|
||||
c = Color.Yellow;
|
||||
break;
|
||||
case STUN_Client.NatType.OpenInternet:
|
||||
case STUN_Client.NatType.FullCone:
|
||||
c = Color.LimeGreen;
|
||||
break;
|
||||
default:
|
||||
c = Color.Black;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
NatTypeStatusLightLabel.ForeColor = c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新 NAT指示灯颜色
|
||||
/// </summary>
|
||||
/// <param name="natType"></param>
|
||||
private void UpdateNatTypeLight(int natType)
|
||||
{
|
||||
Color c;
|
||||
switch (natType)
|
||||
else
|
||||
{
|
||||
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.Visible = false;
|
||||
}
|
||||
|
||||
NatTypeStatusLightLabel.ForeColor = c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -227,5 +180,37 @@ namespace Netch.Forms
|
||||
{
|
||||
StatusLabel.Text += text;
|
||||
}
|
||||
|
||||
public static class StatusPortInfoText
|
||||
{
|
||||
public static int Socks5Port = 0;
|
||||
public static int HttpPort = 0;
|
||||
public static bool ShareLan = false;
|
||||
|
||||
public static string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Socks5Port == 0 && HttpPort == 0)
|
||||
return string.Empty;
|
||||
|
||||
var text = new StringBuilder();
|
||||
if (ShareLan)
|
||||
text.Append(i18N.Translate("Allow other Devices to connect") + " ");
|
||||
|
||||
if (Socks5Port != 0)
|
||||
text.Append($"Socks5 {i18N.Translate("Local Port", ": ")}{Socks5Port}");
|
||||
|
||||
if (HttpPort != 0)
|
||||
{
|
||||
if (Socks5Port != 0)
|
||||
text.Append(" | ");
|
||||
text.Append($"HTTP {i18N.Translate("Local Port", ": ")}{HttpPort}");
|
||||
}
|
||||
|
||||
return $" ({text})";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -6,17 +8,13 @@ using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms.Mode;
|
||||
using Netch.Forms.Server;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Trojan = Netch.Forms.Server.Trojan;
|
||||
using VMess = Netch.Forms.Server.VMess;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -24,11 +22,25 @@ namespace Netch.Forms
|
||||
// 监听电源事件
|
||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
||||
|
||||
ModeComboBox.KeyUp += (sender, args) =>
|
||||
{
|
||||
switch (args.KeyData)
|
||||
{
|
||||
case Keys.Escape:
|
||||
{
|
||||
SelectLastMode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
}
|
||||
|
||||
private void MainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
AddAddServerToolStripMenuItems();
|
||||
|
||||
OnlyInstance.Called += OnCalled;
|
||||
// 计算 ComboBox绘制 目标宽度
|
||||
_eWidth = ServerComboBox.Width / 10;
|
||||
@@ -85,12 +97,12 @@ namespace Netch.Forms
|
||||
});
|
||||
|
||||
|
||||
Task.Run(() =>
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// 检查订阅更新
|
||||
if (Global.Settings.UpdateSubscribeatWhenOpened)
|
||||
{
|
||||
UpdateServersFromSubscribe();
|
||||
await UpdateServersFromSubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -165,57 +177,88 @@ namespace Netch.Forms
|
||||
Show();
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, object> _mainFormText = new Dictionary<string, object>();
|
||||
private bool _textRecorded;
|
||||
|
||||
private void InitText()
|
||||
{
|
||||
ServerToolStripMenuItem.Text = i18N.Translate("Server");
|
||||
ImportServersFromClipboardToolStripMenuItem.Text = i18N.Translate("Import Servers From Clipboard");
|
||||
AddSocks5ServerToolStripMenuItem.Text = i18N.Translate("Add [Socks5] Server");
|
||||
AddShadowsocksServerToolStripMenuItem.Text = i18N.Translate("Add [Shadowsocks] Server");
|
||||
AddShadowsocksRServerToolStripMenuItem.Text = i18N.Translate("Add [ShadowsocksR] Server");
|
||||
AddVMessServerToolStripMenuItem.Text = i18N.Translate("Add [VMess] Server");
|
||||
AddTrojanServerToolStripMenuItem.Text = i18N.Translate("Add [Trojan] Server");
|
||||
ModeToolStripMenuItem.Text = i18N.Translate("Mode");
|
||||
HelpToolStripMenuItem.Text = i18N.Translate("Help");
|
||||
CreateProcessModeToolStripMenuItem.Text = i18N.Translate("Create Process Mode");
|
||||
SubscribeToolStripMenuItem.Text = i18N.Translate("Subscribe");
|
||||
ManageSubscribeLinksToolStripMenuItem.Text = i18N.Translate("Manage Subscribe Links");
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Text = i18N.Translate("Update Servers From Subscribe Links");
|
||||
OptionsToolStripMenuItem.Text = i18N.Translate("Options");
|
||||
ReloadModesToolStripMenuItem.Text = i18N.Translate("Reload Modes");
|
||||
UninstallServiceToolStripMenuItem.Text = i18N.Translate("Uninstall NF Service");
|
||||
CleanDNSCacheToolStripMenuItem.Text = i18N.Translate("Clean DNS Cache");
|
||||
UpdateACLToolStripMenuItem.Text = i18N.Translate("Update ACL");
|
||||
updateACLWithProxyToolStripMenuItem.Text = i18N.Translate("Update ACL with proxy");
|
||||
reinstallTapDriverToolStripMenuItem.Text = i18N.Translate("Reinstall TUN/TAP driver");
|
||||
CheckForUpdatesToolStripMenuItem.Text = i18N.Translate("Check for updates");
|
||||
OpenDirectoryToolStripMenuItem.Text = i18N.Translate("Open Directory");
|
||||
AboutToolStripButton.Text = i18N.Translate("About");
|
||||
NewVersionLabel.Text = i18N.Translate("New version available");
|
||||
// VersionLabel.Text = i18N.Translate("xxx");
|
||||
exitToolStripMenuItem.Text = i18N.Translate("Exit");
|
||||
ConfigurationGroupBox.Text = i18N.Translate("Configuration");
|
||||
ProfileLabel.Text = i18N.Translate("Profile");
|
||||
ModeLabel.Text = i18N.Translate("Mode");
|
||||
ServerLabel.Text = i18N.Translate("Server");
|
||||
// UsedBandwidthLabel.Text = i18N.Translate("Used: 0 KB");
|
||||
// DownloadSpeedLabel.Text = i18N.Translate("↓: 0 KB/s");
|
||||
// UploadSpeedLabel.Text = i18N.Translate("↑: 0 KB/s");
|
||||
NotifyIcon.Text = i18N.Translate("Netch");
|
||||
ShowMainFormToolStripButton.Text = i18N.Translate("Show");
|
||||
ExitToolStripButton.Text = i18N.Translate("Exit");
|
||||
SettingsButton.Text = i18N.Translate("Settings");
|
||||
ProfileGroupBox.Text = i18N.Translate("Profiles");
|
||||
// 加载翻译
|
||||
#region Record English
|
||||
|
||||
if (!_textRecorded)
|
||||
{
|
||||
void RecordText(Component component)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
break;
|
||||
case Control c:
|
||||
_mainFormText.Add(c.Name, c.Text);
|
||||
break;
|
||||
case ToolStripItem c:
|
||||
_mainFormText.Add(c.Name, c.Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Utils.ComponentIterator(this, RecordText);
|
||||
Utils.Utils.ComponentIterator(NotifyMenu, RecordText);
|
||||
_textRecorded = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Translate
|
||||
|
||||
void TranslateText(Component component)
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
break;
|
||||
case Control c:
|
||||
|
||||
c.Text = ControlText(c.Name);
|
||||
break;
|
||||
case ToolStripItem c:
|
||||
c.Text = ControlText(c.Name);
|
||||
break;
|
||||
}
|
||||
|
||||
string ControlText(string name)
|
||||
{
|
||||
var value = _mainFormText[name];
|
||||
if (value.Equals(string.Empty)) return string.Empty;
|
||||
|
||||
if (value is object[] values)
|
||||
return i18N.TranslateFormat(values.First() as string, values.Skip(1).ToArray());
|
||||
else
|
||||
return i18N.Translate(value);
|
||||
}
|
||||
}
|
||||
|
||||
Utils.Utils.ComponentIterator(this, TranslateText);
|
||||
Utils.Utils.ComponentIterator(NotifyMenu, TranslateText);
|
||||
|
||||
#endregion
|
||||
|
||||
UsedBandwidthLabel.Text = $@"{i18N.Translate("Used", ": ")}0 KB";
|
||||
State = State;
|
||||
|
||||
VersionLabel.Text = UpdateChecker.Version;
|
||||
}
|
||||
|
||||
private void Exit(bool forceExit = false)
|
||||
{
|
||||
if (State != State.Waiting && State != State.Stopped && !Global.Settings.StopWhenExited && !forceExit)
|
||||
if (!IsWaiting && !Global.Settings.StopWhenExited && !forceExit)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please press Stop button first"));
|
||||
|
||||
@@ -225,9 +268,8 @@ namespace Netch.Forms
|
||||
|
||||
Hide();
|
||||
NotifyIcon.Visible = false;
|
||||
if (State != State.Waiting && State != State.Stopped)
|
||||
if (!IsWaiting)
|
||||
{
|
||||
// 已启动
|
||||
ControlFun();
|
||||
}
|
||||
|
||||
@@ -270,17 +312,9 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
Form server = Global.Settings.Server[ServerComboBox.SelectedIndex].Type switch
|
||||
{
|
||||
"Socks5" => new Socks5(Global.Settings.Server[ServerComboBox.SelectedIndex]),
|
||||
"SS" => new Shadowsocks(Global.Settings.Server[ServerComboBox.SelectedIndex]),
|
||||
"SSR" => new ShadowsocksR(Global.Settings.Server[ServerComboBox.SelectedIndex]),
|
||||
"VMess" => new VMess(Global.Settings.Server[ServerComboBox.SelectedIndex]),
|
||||
"Trojan" => new Trojan(Global.Settings.Server[ServerComboBox.SelectedIndex]),
|
||||
_ => null
|
||||
};
|
||||
Hide();
|
||||
server?.ShowDialog();
|
||||
var server = Global.Settings.Server[ServerComboBox.SelectedIndex];
|
||||
Servers.GetUtilByTypeName(server.Type).Edit(server);
|
||||
InitServer();
|
||||
Configuration.Save();
|
||||
Show();
|
||||
@@ -290,7 +324,6 @@ namespace Netch.Forms
|
||||
{
|
||||
Enabled = false;
|
||||
StatusText(i18N.Translate("Testing"));
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Run(TestServer);
|
||||
@@ -306,7 +339,7 @@ namespace Netch.Forms
|
||||
private void EditModePictureBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 当前ModeComboBox中至少有一项
|
||||
if (ModeComboBox.Items.Count <= 0 || ModeComboBox.SelectedIndex == -1)
|
||||
if (ModeComboBox.SelectedIndex == -1)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select a mode first"));
|
||||
return;
|
||||
@@ -319,7 +352,6 @@ namespace Netch.Forms
|
||||
{
|
||||
Hide();
|
||||
new Process(selectedMode).ShowDialog();
|
||||
InitMode();
|
||||
Show();
|
||||
break;
|
||||
}
|
||||
@@ -340,10 +372,7 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
|
||||
this.ModeComboBox.Items.Remove(selectedMode);
|
||||
Modes.Delete(selectedMode);
|
||||
|
||||
Modes.Delete((Models.Mode) ModeComboBox.SelectedItem);
|
||||
SelectLastMode();
|
||||
}
|
||||
|
||||
@@ -356,11 +385,21 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedMode = (Models.Server) ServerComboBox.SelectedItem;
|
||||
try
|
||||
{
|
||||
//听说巨硬BUG经常会炸,所以Catch一下 :D
|
||||
Clipboard.SetText(ShareLink.GetShareLink(selectedMode));
|
||||
var server = (Server) ServerComboBox.SelectedItem;
|
||||
string text;
|
||||
if (ModifierKeys == Keys.Control)
|
||||
{
|
||||
text = ShareLink.GetNetchLink(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = ShareLink.GetShareLink(server);
|
||||
}
|
||||
|
||||
Clipboard.SetText(text);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -378,12 +417,9 @@ namespace Netch.Forms
|
||||
}
|
||||
|
||||
var index = ServerComboBox.SelectedIndex;
|
||||
|
||||
Global.Settings.Server.Remove(ServerComboBox.SelectedItem as Models.Server);
|
||||
Global.Settings.Server.Remove(ServerComboBox.SelectedItem as Server);
|
||||
InitServer();
|
||||
|
||||
Configuration.Save();
|
||||
|
||||
if (ServerComboBox.Items.Count > 0)
|
||||
{
|
||||
ServerComboBox.SelectedIndex = index != 0 ? index - 1 : index;
|
||||
@@ -434,12 +470,19 @@ namespace Netch.Forms
|
||||
|
||||
#endregion
|
||||
|
||||
private bool _comboBoxInitialized = false;
|
||||
private bool _comboBoxInitialized;
|
||||
|
||||
private void ModeComboBox_SelectedIndexChanged(object sender, EventArgs o)
|
||||
{
|
||||
if (!_comboBoxInitialized) return;
|
||||
Global.Settings.ModeComboBoxSelectedIndex = ModeComboBox.SelectedIndex;
|
||||
try
|
||||
{
|
||||
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode) ModeComboBox.SelectedItem);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Global.Settings.ModeComboBoxSelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void ServerComboBox_SelectedIndexChanged(object sender, EventArgs o)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Netch.Forms.Mode
|
||||
CheckForIllegalCrossThreadCalls = false;
|
||||
|
||||
Text = "Edit Process Mode";
|
||||
this._mode = mode;
|
||||
_mode = mode;
|
||||
RuleListBox.Items.AddRange(mode.Rule.ToArray());
|
||||
|
||||
#region 禁用文件名更改
|
||||
@@ -110,15 +110,8 @@ namespace Netch.Forms.Mode
|
||||
|
||||
public void ModeForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = i18N.Translate(Text);
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
FilenameLabel.Text = i18N.Translate(FilenameLabel.Text);
|
||||
UseCustomFilenameBox.Text = i18N.Translate(UseCustomFilenameBox.Text);
|
||||
AddButton.Text = i18N.Translate(AddButton.Text);
|
||||
ScanButton.Text = i18N.Translate(ScanButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
DeleteToolStripMenuItem.Text = i18N.Translate(DeleteToolStripMenuItem.Text);
|
||||
i18N.TranslateForm(this);
|
||||
i18N.Translate(contextMenuStrip);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,6 +208,7 @@ namespace Netch.Forms.Mode
|
||||
_mode.Rule.AddRange(RuleListBox.Items.Cast<string>());
|
||||
|
||||
Modes.WriteFile(_mode);
|
||||
Global.MainForm.InitMode();
|
||||
Edited = false;
|
||||
MessageBoxX.Show(i18N.Translate("Mode updated successfully"));
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
public partial class Shadowsocks : Form
|
||||
{
|
||||
private readonly Models.Server _server;
|
||||
|
||||
public Shadowsocks(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = server ?? new Models.Server {EncryptMethod = Global.EncryptMethods.SS[0]};
|
||||
}
|
||||
|
||||
private void Shadowsocks_Load(object sender, EventArgs e)
|
||||
{
|
||||
#region InitText
|
||||
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
EncryptMethodLabel.Text = i18N.Translate(EncryptMethodLabel.Text);
|
||||
PluginLabel.Text = i18N.Translate(PluginLabel.Text);
|
||||
PluginOptionsLabel.Text = i18N.Translate(PluginOptionsLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
EncryptMethodComboBox.Items.AddRange(Global.EncryptMethods.SS.ToArray());
|
||||
|
||||
#endregion
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
EncryptMethodComboBox.SelectedIndex = Global.EncryptMethods.SS.IndexOf(_server.EncryptMethod);
|
||||
PluginTextBox.Text = _server.Plugin;
|
||||
PluginOptionsTextBox.Text = _server.PluginOption;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
{
|
||||
e.DrawBackground();
|
||||
|
||||
if (e.Index >= 0)
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment = StringAlignment.Center
|
||||
};
|
||||
|
||||
var brush = new SolidBrush(cbx.ForeColor);
|
||||
|
||||
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
||||
{
|
||||
brush = SystemBrushes.HighlightText as SolidBrush;
|
||||
}
|
||||
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!int.TryParse(PortTextBox.Text, out var port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "SS";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.EncryptMethod = EncryptMethodComboBox.Text;
|
||||
_server.Plugin = PluginTextBox.Text;
|
||||
_server.PluginOption = PluginOptionsTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
{
|
||||
Global.Settings.Server.Add(_server);
|
||||
}
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
public partial class ShadowsocksR : Form
|
||||
{
|
||||
private readonly Models.Server _server;
|
||||
|
||||
public ShadowsocksR(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = server ?? new Models.Server {EncryptMethod = Global.EncryptMethods.SSR[0]};
|
||||
}
|
||||
|
||||
private void ShadowsocksR_Load(object sender, EventArgs e)
|
||||
{
|
||||
#region InitText
|
||||
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
EncryptMethodLabel.Text = i18N.Translate(EncryptMethodLabel.Text);
|
||||
ProtocolLabel.Text = i18N.Translate(ProtocolLabel.Text);
|
||||
ProtocolParamLabel.Text = i18N.Translate(ProtocolParamLabel.Text);
|
||||
OBFSLabel.Text = i18N.Translate(OBFSLabel.Text);
|
||||
OBFSParamLabel.Text = i18N.Translate(OBFSParamLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
EncryptMethodComboBox.Items.AddRange(Global.EncryptMethods.SSR.ToArray());
|
||||
|
||||
ProtocolComboBox.Items.AddRange(Global.Protocols.ToArray());
|
||||
OBFSComboBox.Items.AddRange(Global.OBFSs.ToArray());
|
||||
|
||||
#endregion
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
EncryptMethodComboBox.SelectedIndex = Global.EncryptMethods.SSR.IndexOf(_server.EncryptMethod);
|
||||
ProtocolComboBox.SelectedIndex = Global.Protocols.IndexOf(_server.Protocol);
|
||||
ProtocolParamTextBox.Text = _server.ProtocolParam;
|
||||
OBFSComboBox.SelectedIndex = Global.OBFSs.IndexOf(_server.OBFS);
|
||||
OBFSOptionParamTextBox.Text = _server.OBFSParam;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
{
|
||||
e.DrawBackground();
|
||||
|
||||
if (e.Index >= 0)
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment = StringAlignment.Center
|
||||
};
|
||||
|
||||
var brush = new SolidBrush(cbx.ForeColor);
|
||||
|
||||
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
||||
{
|
||||
brush = SystemBrushes.HighlightText as SolidBrush;
|
||||
}
|
||||
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!int.TryParse(PortTextBox.Text, out var port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "SSR";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.EncryptMethod = EncryptMethodComboBox.Text;
|
||||
_server.Protocol = ProtocolComboBox.Text;
|
||||
_server.ProtocolParam = ProtocolParamTextBox.Text;
|
||||
_server.OBFS = OBFSComboBox.Text;
|
||||
_server.OBFSParam = OBFSOptionParamTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
{
|
||||
Global.Settings.Server.Add(_server);
|
||||
}
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
public partial class Socks5 : Form
|
||||
{
|
||||
private readonly Models.Server _server;
|
||||
|
||||
public Socks5(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = server ?? new Models.Server();
|
||||
}
|
||||
|
||||
private void Shadowsocks_Load(object sender, EventArgs e)
|
||||
{
|
||||
#region InitText
|
||||
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
UsernameLabel.Text = i18N.Translate(UsernameLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
#endregion
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
UsernameTextBox.Text = _server.Username;
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
{
|
||||
e.DrawBackground();
|
||||
|
||||
if (e.Index >= 0)
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment = StringAlignment.Center
|
||||
};
|
||||
|
||||
var brush = new SolidBrush(cbx.ForeColor);
|
||||
|
||||
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
||||
{
|
||||
brush = SystemBrushes.HighlightText as SolidBrush;
|
||||
}
|
||||
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!int.TryParse(PortTextBox.Text, out var port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "Socks5";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Username = UsernameTextBox.Text;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
{
|
||||
Global.Settings.Server.Add(_server);
|
||||
}
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
public partial class Trojan : Form
|
||||
{
|
||||
private readonly Models.Server _server;
|
||||
|
||||
public Trojan(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = server ?? new Models.Server();
|
||||
}
|
||||
|
||||
private void Trojan_Load(object sender, EventArgs e)
|
||||
{
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
PasswordLabel.Text = i18N.Translate(PasswordLabel.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
{
|
||||
e.DrawBackground();
|
||||
|
||||
if (e.Index >= 0)
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment = StringAlignment.Center
|
||||
};
|
||||
|
||||
var brush = new SolidBrush(cbx.ForeColor);
|
||||
|
||||
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
||||
{
|
||||
brush = SystemBrushes.HighlightText as SolidBrush;
|
||||
}
|
||||
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!int.TryParse(PortTextBox.Text, out var port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "Trojan";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
{
|
||||
Global.Settings.Server.Add(_server);
|
||||
}
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms.Server
|
||||
{
|
||||
public partial class VMess : Form
|
||||
{
|
||||
private static Models.Server _server;
|
||||
|
||||
public VMess(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = server ?? new Models.Server {EncryptMethod = Global.EncryptMethods.VMess[0]};
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
{
|
||||
e.DrawBackground();
|
||||
|
||||
if (e.Index >= 0)
|
||||
{
|
||||
var sf = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment = StringAlignment.Center
|
||||
};
|
||||
|
||||
var brush = new SolidBrush(cbx.ForeColor);
|
||||
|
||||
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
||||
{
|
||||
brush = SystemBrushes.HighlightText as SolidBrush;
|
||||
}
|
||||
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void VMess_Load(object sender, EventArgs e)
|
||||
{
|
||||
#region InitText
|
||||
|
||||
ConfigurationGroupBox.Text = i18N.Translate(ConfigurationGroupBox.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
AddressLabel.Text = i18N.Translate(AddressLabel.Text);
|
||||
UserIDLabel.Text = i18N.Translate(UserIDLabel.Text);
|
||||
AlterIDLabel.Text = i18N.Translate(AlterIDLabel.Text);
|
||||
EncryptMethodLabel.Text = i18N.Translate(EncryptMethodLabel.Text);
|
||||
TransferProtocolLabel.Text = i18N.Translate(TransferProtocolLabel.Text);
|
||||
FakeTypeLabel.Text = i18N.Translate(FakeTypeLabel.Text);
|
||||
HostLabel.Text = i18N.Translate(HostLabel.Text);
|
||||
PathLabel.Text = i18N.Translate(PathLabel.Text);
|
||||
QUICSecurityLabel.Text = i18N.Translate(QUICSecurityLabel.Text);
|
||||
QUICSecretLabel.Text = i18N.Translate(QUICSecretLabel.Text);
|
||||
TLSSecureCheckBox.Text = i18N.Translate(TLSSecureCheckBox.Text);
|
||||
UseMuxCheckBox.Text = i18N.Translate(UseMuxCheckBox.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
|
||||
EncryptMethodComboBox.Items.AddRange(Global.EncryptMethods.VMess.ToArray());
|
||||
TransferProtocolComboBox.Items.AddRange(Global.TransferProtocols.ToArray());
|
||||
FakeTypeComboBox.Items.AddRange(Global.FakeTypes.ToArray());
|
||||
QUICSecurityComboBox.Items.AddRange(Global.EncryptMethods.VMessQUIC.ToArray());
|
||||
|
||||
#endregion
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
UserIDTextBox.Text = _server.UserID;
|
||||
AlterIDTextBox.Text = _server.AlterID.ToString();
|
||||
EncryptMethodComboBox.SelectedIndex = Global.EncryptMethods.VMess.IndexOf(_server.EncryptMethod);
|
||||
TransferProtocolComboBox.SelectedIndex = Global.TransferProtocols.IndexOf(_server.TransferProtocol);
|
||||
FakeTypeComboBox.SelectedIndex = Global.FakeTypes.IndexOf(_server.FakeType);
|
||||
HostTextBox.Text = _server.Host;
|
||||
PathTextBox.Text = _server.Path;
|
||||
QUICSecurityComboBox.SelectedIndex = Global.EncryptMethods.VMessQUIC.IndexOf(_server.QUICSecure);
|
||||
QUICSecretTextBox.Text = _server.QUICSecret;
|
||||
TLSSecureCheckBox.Checked = _server.TLSSecure;
|
||||
UseMuxCheckBox.Checked = _server.UseMux;
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!int.TryParse(PortTextBox.Text, out var port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(AlterIDTextBox.Text, out var alterId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "VMess";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.UserID = UserIDTextBox.Text;
|
||||
_server.AlterID = alterId;
|
||||
_server.EncryptMethod = EncryptMethodComboBox.Text;
|
||||
_server.TransferProtocol = TransferProtocolComboBox.Text;
|
||||
_server.FakeType = FakeTypeComboBox.Text;
|
||||
_server.Host = HostTextBox.Text;
|
||||
_server.Path = PathTextBox.Text;
|
||||
_server.QUICSecure = QUICSecurityComboBox.Text;
|
||||
_server.QUICSecret = QUICSecretTextBox.Text;
|
||||
_server.TLSSecure = TLSSecureCheckBox.Checked;
|
||||
_server.UseMux = UseMuxCheckBox.Checked;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
{
|
||||
Global.Settings.Server.Add(_server);
|
||||
}
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Netch/Forms/SettingForm.Designer.cs
generated
17
Netch/Forms/SettingForm.Designer.cs
generated
@@ -40,6 +40,7 @@
|
||||
this.TUNTAPGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.UseFakeDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ProxyDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ICSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.UseCustomDNSCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.TUNTAPDNSLabel = new System.Windows.Forms.Label();
|
||||
this.TUNTAPDNSTextBox = new System.Windows.Forms.TextBox();
|
||||
@@ -160,6 +161,7 @@
|
||||
//
|
||||
this.TUNTAPGroupBox.Controls.Add(this.UseFakeDNSCheckBox);
|
||||
this.TUNTAPGroupBox.Controls.Add(this.ProxyDNSCheckBox);
|
||||
this.TUNTAPGroupBox.Controls.Add(this.ICSCheckBox);
|
||||
this.TUNTAPGroupBox.Controls.Add(this.UseCustomDNSCheckBox);
|
||||
this.TUNTAPGroupBox.Controls.Add(this.TUNTAPDNSLabel);
|
||||
this.TUNTAPGroupBox.Controls.Add(this.TUNTAPDNSTextBox);
|
||||
@@ -184,6 +186,7 @@
|
||||
this.UseFakeDNSCheckBox.Size = new System.Drawing.Size(110, 21);
|
||||
this.UseFakeDNSCheckBox.TabIndex = 11;
|
||||
this.UseFakeDNSCheckBox.Text = "Use Fake DNS";
|
||||
this.UseFakeDNSCheckBox.Visible = false;
|
||||
this.UseFakeDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ProxyDNSCheckBox
|
||||
@@ -196,6 +199,18 @@
|
||||
this.ProxyDNSCheckBox.Text = "Proxy DNS in Mode 2";
|
||||
this.ProxyDNSCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ICSCheckBox
|
||||
//
|
||||
this.ICSCheckBox.AutoSize = true;
|
||||
this.ICSCheckBox.Location = new System.Drawing.Point(261, 160);
|
||||
this.ICSCheckBox.Name = "ICSCheckBox";
|
||||
this.ICSCheckBox.Size = new System.Drawing.Size(46, 21);
|
||||
this.ICSCheckBox.TabIndex = 5;
|
||||
this.ICSCheckBox.Text = "ICS";
|
||||
this.ICSCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.ICSCheckBox.UseVisualStyleBackColor = true;
|
||||
this.ICSCheckBox.CheckedChanged += new System.EventHandler(this.ICSCheckBox_CheckedChanged);
|
||||
//
|
||||
// UseCustomDNSCheckBox
|
||||
//
|
||||
this.UseCustomDNSCheckBox.AutoSize = true;
|
||||
@@ -558,6 +573,8 @@
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
private System.Windows.Forms.CheckBox ICSCheckBox;
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox PortGroupBox;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Controllers;
|
||||
using Netch.Utils;
|
||||
using TaskScheduler;
|
||||
|
||||
@@ -17,87 +17,28 @@ namespace Netch.Forms
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
TUNTAPDNSTextBox.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
TUNTAPDNSTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
if (Global.Settings.TUNTAP.DNS.Count > 0)
|
||||
{
|
||||
var dns = "";
|
||||
foreach (var ip in Global.Settings.TUNTAP.DNS)
|
||||
{
|
||||
dns += ip;
|
||||
dns += ',';
|
||||
}
|
||||
|
||||
dns = dns.Trim();
|
||||
TUNTAPDNSTextBox.Text = dns.Substring(0, dns.Length - 1);
|
||||
}
|
||||
// 如果 DNS 为空,设置为默认 DNS 1.1.1.1
|
||||
else
|
||||
{
|
||||
Global.Settings.TUNTAP.DNS.Add("1.1.1.1");
|
||||
TUNTAPDNSTextBox.Text = "1.1.1.1";
|
||||
}
|
||||
}
|
||||
|
||||
private void InitValue()
|
||||
{
|
||||
// Local Port
|
||||
Socks5PortTextBox.Text = Global.Settings.Socks5LocalPort.ToString();
|
||||
HTTPPortTextBox.Text = Global.Settings.HTTPLocalPort.ToString();
|
||||
RedirectorTextBox.Text = Global.Settings.RedirectorTCPPort.ToString();
|
||||
switch (Global.Settings.LocalAddress)
|
||||
AllowDevicesCheckBox.Checked = Global.Settings.LocalAddress switch
|
||||
{
|
||||
case "127.0.0.1":
|
||||
AllowDevicesCheckBox.Checked = false;
|
||||
break;
|
||||
case "0.0.0.0":
|
||||
AllowDevicesCheckBox.Checked = true;
|
||||
break;
|
||||
default:
|
||||
Global.Settings.LocalAddress = "127.0.0.1";
|
||||
AllowDevicesCheckBox.Checked = false;
|
||||
break;
|
||||
}
|
||||
"127.0.0.1" => false,
|
||||
"0.0.0.0" => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
// TUN/TAP
|
||||
TUNTAPAddressTextBox.Text = Global.Settings.TUNTAP.Address;
|
||||
TUNTAPNetmaskTextBox.Text = Global.Settings.TUNTAP.Netmask;
|
||||
TUNTAPGatewayTextBox.Text = Global.Settings.TUNTAP.Gateway;
|
||||
UseCustomDNSCheckBox.Checked = Global.Settings.TUNTAP.UseCustomDNS;
|
||||
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
|
||||
ProxyDNSCheckBox.Checked = Global.Settings.TUNTAP.ProxyDNS;
|
||||
UseFakeDNSCheckBox.Checked = Global.Settings.TUNTAP.UseFakeDNS;
|
||||
if (Global.Settings.TUNTAP.DNS.Count > 0)
|
||||
{
|
||||
var dns = "";
|
||||
foreach (var ip in Global.Settings.TUNTAP.DNS)
|
||||
{
|
||||
dns += ip;
|
||||
dns += ',';
|
||||
}
|
||||
|
||||
dns = dns.Trim();
|
||||
TUNTAPDNSTextBox.Text = dns.Substring(0, dns.Length - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果 DNS 为空,设置为默认 DNS 1.1.1.1
|
||||
Global.Settings.TUNTAP.DNS.Add("1.1.1.1");
|
||||
TUNTAPDNSTextBox.Text = "1.1.1.1";
|
||||
}
|
||||
|
||||
if (!UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
TUNTAPDNSTextBox.Enabled = false;
|
||||
}
|
||||
ICSCheckBox.Checked = ICSController.Enabled;
|
||||
|
||||
// Behavior
|
||||
ExitWhenClosedCheckBox.Checked = Global.Settings.ExitWhenClosed;
|
||||
@@ -107,50 +48,38 @@ namespace Netch.Forms
|
||||
RunAtStartupCheckBox.Checked = Global.Settings.RunAtStartup;
|
||||
CheckUpdateWhenOpenedCheckBox.Checked = Global.Settings.CheckUpdateWhenOpened;
|
||||
BootShadowsocksFromDLLCheckBox.Checked = Global.Settings.BootShadowsocksFromDLL;
|
||||
ModifySystemDNSCheckBox.Checked = Global.Settings.ModifySystemDNS;
|
||||
CheckBetaUpdateCheckBox.Checked = Global.Settings.CheckBetaUpdate;
|
||||
ModifySystemDNSCheckBox.Checked = Global.Settings.ModifySystemDNS;
|
||||
UpdateSubscribeatWhenOpenedCheckBox.Checked = Global.Settings.UpdateSubscribeatWhenOpened;
|
||||
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
TcpingAtStartedCheckBox.Checked = Global.Settings.StartedTcping;
|
||||
DetectionIntervalTextBox.Text = Global.Settings.StartedTcping_Interval.ToString();
|
||||
InitSTUN();
|
||||
AclAddrTextBox.Text = Global.Settings.ACL;
|
||||
LanguageComboBox.Items.AddRange(i18N.GetTranslateList().ToArray());
|
||||
LanguageComboBox.SelectedItem = Global.Settings.Language;
|
||||
InitSTUN();
|
||||
}
|
||||
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
TUNTAPDNSTextBox.Enabled = UseCustomDNSCheckBox.Checked;
|
||||
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
|
||||
? Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}")
|
||||
: "1.1.1.1";
|
||||
}
|
||||
else
|
||||
{
|
||||
TUNTAPDNSTextBox.Text = "Local DNS";
|
||||
}
|
||||
}
|
||||
|
||||
private void InitText()
|
||||
{
|
||||
Text = i18N.Translate(Text);
|
||||
|
||||
PortGroupBox.Text = i18N.Translate(PortGroupBox.Text);
|
||||
AllowDevicesCheckBox.Text = i18N.Translate(AllowDevicesCheckBox.Text);
|
||||
TUNTAPAddressLabel.Text = i18N.Translate(TUNTAPAddressLabel.Text);
|
||||
TUNTAPNetmaskLabel.Text = i18N.Translate(TUNTAPNetmaskLabel.Text);
|
||||
TUNTAPGatewayLabel.Text = i18N.Translate(TUNTAPGatewayLabel.Text);
|
||||
UseCustomDNSCheckBox.Text = i18N.Translate(UseCustomDNSCheckBox.Text);
|
||||
ProxyDNSCheckBox.Text = i18N.Translate(ProxyDNSCheckBox.Text);
|
||||
UseFakeDNSCheckBox.Text = i18N.Translate(UseFakeDNSCheckBox.Text);
|
||||
GlobalBypassIPsButton.Text = i18N.Translate(GlobalBypassIPsButton.Text);
|
||||
ControlButton.Text = i18N.Translate(ControlButton.Text);
|
||||
BootShadowsocksFromDLLCheckBox.Text = i18N.Translate(BootShadowsocksFromDLLCheckBox.Text);
|
||||
ModifySystemDNSCheckBox.Text = i18N.Translate(ModifySystemDNSCheckBox.Text);
|
||||
CheckBetaUpdateCheckBox.Text = i18N.Translate(CheckBetaUpdateCheckBox.Text);
|
||||
BehaviorGroupBox.Text = i18N.Translate(BehaviorGroupBox.Text);
|
||||
ExitWhenClosedCheckBox.Text = i18N.Translate(ExitWhenClosedCheckBox.Text);
|
||||
StopWhenExitedCheckBox.Text = i18N.Translate(StopWhenExitedCheckBox.Text);
|
||||
StartWhenOpenedCheckBox.Text = i18N.Translate(StartWhenOpenedCheckBox.Text);
|
||||
MinimizeWhenStartedCheckBox.Text = i18N.Translate(MinimizeWhenStartedCheckBox.Text);
|
||||
RunAtStartupCheckBox.Text = i18N.Translate(RunAtStartupCheckBox.Text);
|
||||
UpdateSubscribeatWhenOpenedCheckBox.Text = i18N.Translate(UpdateSubscribeatWhenOpenedCheckBox.Text);
|
||||
CheckUpdateWhenOpenedCheckBox.Text = i18N.Translate(CheckUpdateWhenOpenedCheckBox.Text);
|
||||
ProfileCountLabel.Text = i18N.Translate(ProfileCountLabel.Text);
|
||||
TcpingAtStartedCheckBox.Text = i18N.Translate(TcpingAtStartedCheckBox.Text);
|
||||
DetectionIntervalLabel.Text = i18N.Translate(DetectionIntervalLabel.Text);
|
||||
STUNServerLabel.Text = i18N.Translate(STUNServerLabel.Text);
|
||||
AclLabel.Text = i18N.Translate(AclLabel.Text);
|
||||
LanguageLabel.Text = i18N.Translate(LanguageLabel.Text);
|
||||
i18N.TranslateForm(this);
|
||||
}
|
||||
|
||||
private void InitSTUN()
|
||||
@@ -170,6 +99,7 @@ namespace Netch.Forms
|
||||
|
||||
private void SettingForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
UseFakeDNSCheckBox.Visible = Global.Flags.SupportFakeDns;
|
||||
InitText();
|
||||
InitValue();
|
||||
}
|
||||
@@ -183,25 +113,229 @@ namespace Netch.Forms
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
#region Check
|
||||
|
||||
#region Port
|
||||
|
||||
int socks5LocalPort;
|
||||
int httpLocalPort;
|
||||
int redirectorTCPPort;
|
||||
try
|
||||
{
|
||||
socks5LocalPort = int.Parse(Socks5PortTextBox.Text);
|
||||
httpLocalPort = int.Parse(HTTPPortTextBox.Text);
|
||||
redirectorTCPPort = int.Parse(RedirectorTextBox.Text);
|
||||
|
||||
static void CheckPort(string portName, int port, int originPort, PortType portType = PortType.Both)
|
||||
{
|
||||
if (port <= 0 || port > 65536)
|
||||
throw new FormatException();
|
||||
|
||||
if (port == originPort)
|
||||
return;
|
||||
|
||||
if (PortHelper.PortInUse(port, portType))
|
||||
{
|
||||
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
|
||||
throw new PortInUseException();
|
||||
}
|
||||
}
|
||||
|
||||
CheckPort("Socks5", socks5LocalPort, Global.Settings.Socks5LocalPort);
|
||||
CheckPort("HTTP", httpLocalPort, Global.Settings.HTTPLocalPort);
|
||||
CheckPort("RedirectorTCP", redirectorTCPPort, Global.Settings.RedirectorTCPPort);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
switch (exception)
|
||||
{
|
||||
case FormatException _:
|
||||
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
|
||||
break;
|
||||
case PortInUseException _:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TUNTAP
|
||||
|
||||
var dns = new string[0];
|
||||
try
|
||||
{
|
||||
IPAddress.Parse(TUNTAPAddressTextBox.Text);
|
||||
IPAddress.Parse(TUNTAPNetmaskTextBox.Text);
|
||||
IPAddress.Parse(TUNTAPGatewayTextBox.Text);
|
||||
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
dns = TUNTAPDNSTextBox.Text.Split(',').Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim())
|
||||
.ToArray();
|
||||
if (dns.Any())
|
||||
{
|
||||
foreach (var ip in dns)
|
||||
IPAddress.Parse(ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show("DNS can not be empty");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is FormatException)
|
||||
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
|
||||
|
||||
TUNTAPAddressTextBox.Text = Global.Settings.TUNTAP.Address;
|
||||
TUNTAPNetmaskTextBox.Text = Global.Settings.TUNTAP.Netmask;
|
||||
TUNTAPGatewayTextBox.Text = Global.Settings.TUNTAP.Gateway;
|
||||
UseCustomDNSCheckBox.Checked = Global.Settings.TUNTAP.UseCustomDNS;
|
||||
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
{
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Behavior
|
||||
|
||||
// Profile
|
||||
int profileCount;
|
||||
try
|
||||
{
|
||||
profileCount = int.Parse(ProfileCountTextBox.Text);
|
||||
|
||||
if (profileCount <= -1)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBoxX.Show(i18N.Translate("ProfileCount value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Started TCPing Interval
|
||||
int detectionInterval;
|
||||
try
|
||||
{
|
||||
detectionInterval = int.Parse(DetectionIntervalTextBox.Text);
|
||||
|
||||
if (detectionInterval <= 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBoxX.Show(i18N.Translate("Detection interval value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// STUN
|
||||
string stunServer;
|
||||
int stunServerPort;
|
||||
try
|
||||
{
|
||||
var stun = STUN_ServerComboBox.Text.Split(':');
|
||||
stunServer = stun[0];
|
||||
|
||||
stunServerPort = 3478;
|
||||
if (stun.Length > 1)
|
||||
stunServerPort = int.Parse(stun[1]);
|
||||
|
||||
if (stunServerPort <= 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBoxX.Show(i18N.Translate("STUN_ServerPort value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
|
||||
#region Port
|
||||
|
||||
Global.Settings.Socks5LocalPort = socks5LocalPort;
|
||||
Global.Settings.HTTPLocalPort = httpLocalPort;
|
||||
Global.Settings.RedirectorTCPPort = redirectorTCPPort;
|
||||
Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1";
|
||||
|
||||
#endregion
|
||||
|
||||
#region TUNTAP
|
||||
|
||||
Global.Settings.TUNTAP.Address = TUNTAPAddressTextBox.Text;
|
||||
Global.Settings.TUNTAP.Netmask = TUNTAPNetmaskTextBox.Text;
|
||||
Global.Settings.TUNTAP.Gateway = TUNTAPGatewayTextBox.Text;
|
||||
Global.Settings.TUNTAP.UseCustomDNS = UseCustomDNSCheckBox.Checked;
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
{
|
||||
Global.Settings.TUNTAP.DNS.Clear();
|
||||
Global.Settings.TUNTAP.DNS.AddRange(dns);
|
||||
}
|
||||
|
||||
Global.Settings.TUNTAP.ProxyDNS = ProxyDNSCheckBox.Checked;
|
||||
Global.Settings.TUNTAP.UseFakeDNS = UseFakeDNSCheckBox.Checked;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Behavior
|
||||
|
||||
Global.Settings.ExitWhenClosed = ExitWhenClosedCheckBox.Checked;
|
||||
Global.Settings.StopWhenExited = StopWhenExitedCheckBox.Checked;
|
||||
Global.Settings.StartWhenOpened = StartWhenOpenedCheckBox.Checked;
|
||||
Global.Settings.CheckUpdateWhenOpened = CheckUpdateWhenOpenedCheckBox.Checked;
|
||||
Global.Settings.CheckBetaUpdate = CheckBetaUpdateCheckBox.Checked;
|
||||
Global.Settings.UpdateSubscribeatWhenOpened = UpdateSubscribeatWhenOpenedCheckBox.Checked;
|
||||
Global.Settings.MinimizeWhenStarted = MinimizeWhenStartedCheckBox.Checked;
|
||||
Global.Settings.RunAtStartup = RunAtStartupCheckBox.Checked;
|
||||
Global.Settings.CheckUpdateWhenOpened = CheckUpdateWhenOpenedCheckBox.Checked;
|
||||
Global.Settings.BootShadowsocksFromDLL = BootShadowsocksFromDLLCheckBox.Checked;
|
||||
Global.Settings.CheckBetaUpdate = CheckBetaUpdateCheckBox.Checked;
|
||||
Global.Settings.ModifySystemDNS = ModifySystemDNSCheckBox.Checked;
|
||||
Global.Settings.UpdateSubscribeatWhenOpened = UpdateSubscribeatWhenOpenedCheckBox.Checked;
|
||||
|
||||
Global.Settings.ProfileCount = profileCount;
|
||||
Global.Settings.StartedTcping = TcpingAtStartedCheckBox.Checked;
|
||||
Global.Settings.StartedTcping_Interval = detectionInterval;
|
||||
Global.Settings.STUN_Server = stunServer;
|
||||
Global.Settings.STUN_Server_Port = stunServerPort;
|
||||
Global.Settings.ACL = AclAddrTextBox.Text;
|
||||
Global.Settings.Language = LanguageComboBox.SelectedItem.ToString();
|
||||
|
||||
// 开机自启判断
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Register Startup Item
|
||||
|
||||
var scheduler = new TaskSchedulerClass();
|
||||
scheduler.Connect();
|
||||
var folder = scheduler.GetFolder("\\");
|
||||
|
||||
var taskIsExists = false;
|
||||
try
|
||||
|
||||
{
|
||||
folder.GetTask("Netch Startup");
|
||||
taskIsExists = true;
|
||||
@@ -211,7 +345,7 @@ namespace Netch.Forms
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (RunAtStartupCheckBox.Checked)
|
||||
if (Global.Settings.RunAtStartup)
|
||||
{
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
@@ -233,185 +367,35 @@ namespace Netch.Forms
|
||||
folder.RegisterTaskDefinition("Netch Startup", task, (int) _TASK_CREATION.TASK_CREATE, null, null,
|
||||
_TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (taskIsExists)
|
||||
folder.DeleteTask("Netch Startup", 0);
|
||||
}
|
||||
|
||||
// 端口检查
|
||||
if (!CheckPortText("Socks5", ref Socks5PortTextBox, ref Global.Settings.Socks5LocalPort))
|
||||
return;
|
||||
if (!CheckPortText("HTTP", ref HTTPPortTextBox, ref Global.Settings.HTTPLocalPort))
|
||||
return;
|
||||
if (!CheckPortText("RedirectorTCP", ref RedirectorTextBox, ref Global.Settings.RedirectorTCPPort, PortType.TCP))
|
||||
return;
|
||||
Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1";
|
||||
try
|
||||
{
|
||||
var Address = IPAddress.Parse(TUNTAPAddressTextBox.Text);
|
||||
var Netmask = IPAddress.Parse(TUNTAPNetmaskTextBox.Text);
|
||||
var Gateway = IPAddress.Parse(TUNTAPGatewayTextBox.Text);
|
||||
#endregion
|
||||
|
||||
var DNS = new List<IPAddress>();
|
||||
foreach (var ip in TUNTAPDNSTextBox.Text.Split(','))
|
||||
{
|
||||
DNS.Add(IPAddress.Parse(ip));
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("IP address format illegal. Try again."));
|
||||
|
||||
TUNTAPAddressTextBox.Text = Global.Settings.TUNTAP.Address;
|
||||
TUNTAPNetmaskTextBox.Text = Global.Settings.TUNTAP.Netmask;
|
||||
TUNTAPGatewayTextBox.Text = Global.Settings.TUNTAP.Gateway;
|
||||
|
||||
var DNS = "";
|
||||
foreach (var ip in Global.Settings.TUNTAP.DNS)
|
||||
{
|
||||
DNS += ip;
|
||||
DNS += ',';
|
||||
}
|
||||
|
||||
DNS = DNS.Trim();
|
||||
TUNTAPDNSTextBox.Text = DNS.Substring(0, DNS.Length - 1);
|
||||
UseCustomDNSCheckBox.Checked = Global.Settings.TUNTAP.UseCustomDNS;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ProfileCount = int.Parse(ProfileCountTextBox.Text);
|
||||
|
||||
if (ProfileCount > -1)
|
||||
{
|
||||
Global.Settings.ProfileCount = ProfileCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBoxX.Show(i18N.Translate("ProfileCount value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var stun = STUN_ServerComboBox.Text.Split(':');
|
||||
var STUN_Server = stun[0];
|
||||
Global.Settings.STUN_Server = STUN_Server;
|
||||
|
||||
var STUN_ServerPort = 3478;
|
||||
if (stun.Length > 1)
|
||||
STUN_ServerPort = int.Parse(stun[1]);
|
||||
|
||||
if (STUN_ServerPort > 0)
|
||||
{
|
||||
Global.Settings.STUN_Server_Port = STUN_ServerPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBoxX.Show(i18N.Translate("STUN_ServerPort value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Global.Settings.StartedTcping = TcpingAtStartedCheckBox.Checked;
|
||||
|
||||
var DetectionInterval = int.Parse(DetectionIntervalTextBox.Text);
|
||||
|
||||
if (DetectionInterval > 0)
|
||||
{
|
||||
Global.Settings.StartedTcping_Interval = DetectionInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
|
||||
MessageBoxX.Show(i18N.Translate("Detection interval value illegal. Try again."));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Global.Settings.ACL = AclAddrTextBox.Text;
|
||||
Global.Settings.TUNTAP.Address = TUNTAPAddressTextBox.Text;
|
||||
Global.Settings.TUNTAP.Netmask = TUNTAPNetmaskTextBox.Text;
|
||||
Global.Settings.TUNTAP.Gateway = TUNTAPGatewayTextBox.Text;
|
||||
Global.Settings.TUNTAP.DNS.Clear();
|
||||
foreach (var ip in TUNTAPDNSTextBox.Text.Split(','))
|
||||
{
|
||||
Global.Settings.TUNTAP.DNS.Add(ip);
|
||||
}
|
||||
|
||||
Global.Settings.TUNTAP.UseCustomDNS = UseCustomDNSCheckBox.Checked;
|
||||
Global.Settings.TUNTAP.ProxyDNS = ProxyDNSCheckBox.Checked;
|
||||
Global.Settings.TUNTAP.UseFakeDNS = UseFakeDNSCheckBox.Checked;
|
||||
Global.Settings.ModifySystemDNS = ModifySystemDNSCheckBox.Checked;
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="portName"></param>
|
||||
/// <param name="portTextBox"></param>
|
||||
/// <param name="originPort"></param>
|
||||
/// <param name="portType"></param>
|
||||
/// <returns></returns>
|
||||
private bool CheckPortText(string portName, ref TextBox portTextBox, ref int originPort, PortType portType = PortType.Both)
|
||||
private async void ICSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
// 端口检查
|
||||
try
|
||||
ICSCheckBox.Enabled = false;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var port = int.Parse(portTextBox.Text);
|
||||
|
||||
if (port <= 0 || port >= 65536)
|
||||
if (ICSCheckBox.Checked)
|
||||
{
|
||||
throw new FormatException();
|
||||
if (!ICSController.Enabled)
|
||||
ICSCheckBox.Checked = ICSController.Enable();
|
||||
}
|
||||
|
||||
if (port == originPort)
|
||||
else
|
||||
{
|
||||
return true;
|
||||
ICSController.Disable();
|
||||
}
|
||||
|
||||
if (PortHelper.PortInUse(port, portType))
|
||||
{
|
||||
MessageBoxX.Show(i18N.TranslateFormat("The {0} port is in use.", portName));
|
||||
return false;
|
||||
}
|
||||
|
||||
originPort = port;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Port value illegal. Try again."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
ICSCheckBox.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,16 +32,8 @@ namespace Netch.Forms
|
||||
|
||||
private void SubscribeForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = i18N.Translate(Text);
|
||||
RemarkColumnHeader.Text = i18N.Translate(RemarkColumnHeader.Text);
|
||||
LinkColumnHeader.Text = i18N.Translate(LinkColumnHeader.Text);
|
||||
UseSelectedServerCheckBox.Text = i18N.Translate(UseSelectedServerCheckBox.Text);
|
||||
DeleteToolStripMenuItem.Text = i18N.Translate(DeleteToolStripMenuItem.Text);
|
||||
CopyLinkToolStripMenuItem.Text = i18N.Translate(CopyLinkToolStripMenuItem.Text);
|
||||
RemarkLabel.Text = i18N.Translate(RemarkLabel.Text);
|
||||
LinkLabel.Text = i18N.Translate(LinkLabel.Text);
|
||||
ClearButton.Text = i18N.Translate(ClearButton.Text);
|
||||
AddButton.Text = i18N.Translate(AddButton.Text);
|
||||
i18N.TranslateForm(this);
|
||||
i18N.TranslateForm(pContextMenuStrip);
|
||||
|
||||
ResetEditingGroup();
|
||||
|
||||
|
||||
162
Netch/Global.cs
162
Netch/Global.cs
@@ -1,162 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Controllers;
|
||||
using Netch.Forms;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public static class Global
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 换行
|
||||
/// </summary>
|
||||
public const string EOF = "\r\n";
|
||||
|
||||
public static readonly string NetchDir = Application.StartupPath;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 主窗体的静态实例
|
||||
/// </summary>
|
||||
public static Forms.MainForm MainForm;
|
||||
public static MainForm MainForm;
|
||||
|
||||
/// <summary>
|
||||
/// SS/SSR 加密方式
|
||||
/// </summary>
|
||||
public static class EncryptMethods
|
||||
public static class Flags
|
||||
{
|
||||
/// <summary>
|
||||
/// SS 加密列表
|
||||
/// </summary>
|
||||
public static List<string> SS = new List<string>
|
||||
static Flags()
|
||||
{
|
||||
"rc4-md5",
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"bf-cfb",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
};
|
||||
Task.Run(() =>
|
||||
{
|
||||
SupportFakeDns = new TUNTAPController().TestFakeDNS();
|
||||
IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSR 加密列表
|
||||
/// </summary>
|
||||
public static List<string> SSR = new List<string>
|
||||
{
|
||||
"none",
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
};
|
||||
/// <summary>
|
||||
/// VMess 解密列表
|
||||
/// </summary>
|
||||
public static List<string> VMess = new List<string>
|
||||
{
|
||||
"auto",
|
||||
"none",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// VMess QUIC 加密列表
|
||||
/// </summary>
|
||||
public static List<string> VMessQUIC = new List<string>
|
||||
{
|
||||
"none",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305"
|
||||
};
|
||||
public static bool SupportFakeDns;
|
||||
public static bool IsWindows10Upper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSR 协议列表
|
||||
/// </summary>
|
||||
public static List<string> Protocols = new List<string>
|
||||
{
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_md5",
|
||||
"auth_aes128_sha1",
|
||||
"auth_chain_a"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// SSR 混淆列表
|
||||
/// 出口适配器
|
||||
/// </summary>
|
||||
public static List<string> OBFSs = new List<string>
|
||||
{
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"tls1.2_ticket_auth"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// V2Ray 传输协议
|
||||
/// </summary>
|
||||
public static List<string> TransferProtocols = new List<string>
|
||||
{
|
||||
"tcp",
|
||||
"kcp",
|
||||
"ws",
|
||||
"h2",
|
||||
"quic"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// V2Ray 伪装类型
|
||||
/// </summary>
|
||||
public static List<string> FakeTypes = new List<string>
|
||||
{
|
||||
"none",
|
||||
"http",
|
||||
"srtp",
|
||||
"utp",
|
||||
"wechat-video",
|
||||
"dtls",
|
||||
"wireguard"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 适配器
|
||||
/// </summary>
|
||||
public static class Adapter
|
||||
public static class Outbound
|
||||
{
|
||||
/// <summary>
|
||||
/// 索引
|
||||
@@ -166,12 +54,14 @@ namespace Netch
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public static IPAddress Address;
|
||||
public static IPAddress Address => Adapter.GetIPProperties().UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork).Address;
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public static IPAddress Gateway;
|
||||
|
||||
public static NetworkInterface Adapter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,11 +88,11 @@ namespace Netch
|
||||
/// <summary>
|
||||
/// 用于读取和写入的配置
|
||||
/// </summary>
|
||||
public static Models.Setting Settings = new Models.Setting();
|
||||
public static Setting Settings = new Setting();
|
||||
|
||||
/// <summary>
|
||||
/// 用于存储模式
|
||||
/// </summary>
|
||||
public static readonly List<Models.Mode> Modes = new List<Models.Mode>();
|
||||
public static readonly List<Mode> Modes = new List<Mode>();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Netch/Models/IServerUtil.cs
Normal file
42
Netch/Models/IServerUtil.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
public interface IServerUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection order basis
|
||||
/// </summary>
|
||||
ushort Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Server.Type
|
||||
/// </summary>
|
||||
string TypeName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Protocol Name
|
||||
/// </summary>
|
||||
string FullName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Support URI
|
||||
/// </summary>
|
||||
string[] UriScheme { get; }
|
||||
|
||||
Server ParseJObject(JObject j);
|
||||
|
||||
public void Edit(Server s);
|
||||
|
||||
public void Create();
|
||||
|
||||
string GetShareLink(Server server);
|
||||
|
||||
public abstract ServerController GetController();
|
||||
|
||||
public abstract IEnumerable<Server> ParseUri(string text);
|
||||
|
||||
bool CheckServer(Server s);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class LegacyServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark;
|
||||
|
||||
/// <summary>
|
||||
/// 组
|
||||
/// </summary>
|
||||
public string Group = "None";
|
||||
|
||||
/// <summary>
|
||||
/// 类型(Socks5、Shadowsocks、ShadowsocksR、VMess)
|
||||
/// </summary>
|
||||
public string Type;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public string Address;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public int Port;
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
public string Username;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password;
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID(V2)
|
||||
/// </summary>
|
||||
public string UserID = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 额外 ID(V2)
|
||||
/// </summary>
|
||||
public int AlterID = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod;
|
||||
|
||||
/// <summary>
|
||||
/// 协议
|
||||
/// </summary>
|
||||
public string Protocol;
|
||||
|
||||
/// <summary>
|
||||
/// 协议参数
|
||||
/// </summary>
|
||||
public string ProtocolParam;
|
||||
|
||||
/// <summary>
|
||||
/// 混淆(SSR)/ 插件(SS)
|
||||
/// </summary>
|
||||
public string OBFS;
|
||||
|
||||
/// <summary>
|
||||
/// 混淆参数(SSR)/ 插件参数(SS)
|
||||
/// </summary>
|
||||
public string OBFSParam;
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议(V2)
|
||||
/// </summary>
|
||||
public string TransferProtocol = "tcp";
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型(V2)
|
||||
/// </summary>
|
||||
public string FakeType = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名(V2:HTTP、WebSocket、HTTP/2)
|
||||
/// </summary>
|
||||
public string Host = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 传输路径(V2:WebSocket、HTTP/2)
|
||||
/// </summary>
|
||||
public string Path = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密方式(V2)
|
||||
/// </summary>
|
||||
public string QUICSecurity = "none";
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密密钥(V2)
|
||||
/// </summary>
|
||||
public string QUICSecret = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// TLS 底层传输安全(V2)
|
||||
/// </summary>
|
||||
public bool TLSSecure = false;
|
||||
|
||||
/// <summary>
|
||||
/// 延迟
|
||||
/// </summary>
|
||||
public int Delay = -1;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于读取和写入的配置的类
|
||||
/// </summary>
|
||||
public class LegacySetting
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器选择位置
|
||||
/// </summary>
|
||||
public int ServerComboBoxSelectedIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 模式选择位置
|
||||
/// </summary>
|
||||
public int ModeComboBoxSelectedIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 本地端口
|
||||
/// </summary>
|
||||
public int HTTPLocalPort = 2802;
|
||||
|
||||
/// <summary>
|
||||
/// Socks5 本地端口
|
||||
/// </summary>
|
||||
public int Socks5LocalPort = 2801;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 和 Socks5 本地代理地址
|
||||
/// </summary>
|
||||
public string LocalAddress = "127.0.0.1";
|
||||
|
||||
/// <summary>
|
||||
/// Redirector TCP 占用端口
|
||||
/// </summary>
|
||||
public int RedirectorTCPPort = 2800;
|
||||
|
||||
/// <summary>
|
||||
/// TUNTAP 适配器配置
|
||||
/// </summary>
|
||||
public TUNTAPConfig TUNTAP = new TUNTAPConfig();
|
||||
|
||||
/// <summary>
|
||||
/// 服务器列表
|
||||
/// </summary>
|
||||
public List<LegacyServer> Server = new List<LegacyServer>();
|
||||
|
||||
/// <summary>
|
||||
/// 订阅链接列表
|
||||
/// </summary>
|
||||
public List<SubscribeLink> SubscribeLink = new List<SubscribeLink>();
|
||||
|
||||
/// <summary>
|
||||
/// 全局绕过 IP 列表
|
||||
/// </summary>
|
||||
public List<string> BypassIPs = new List<string>();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace Netch.Models
|
||||
{
|
||||
public class STUN_Client
|
||||
{
|
||||
public enum NatType
|
||||
{
|
||||
UdpBlocked,
|
||||
OpenInternet,
|
||||
SymmetricUdpFirewall,
|
||||
FullCone,
|
||||
RestrictedCone,
|
||||
PortRestrictedCone,
|
||||
Symmetric
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using MaxMind.GeoIP2;
|
||||
using Netch.Utils;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
@@ -19,7 +17,7 @@ namespace Netch.Models
|
||||
public string Group = "None";
|
||||
|
||||
/// <summary>
|
||||
/// 代理类型(HTTP、HTTPS、Socks5、SS、SSR、VMess)
|
||||
/// 代理类型
|
||||
/// </summary>
|
||||
public string Type;
|
||||
|
||||
@@ -38,101 +36,6 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public int Port;
|
||||
|
||||
/// <summary>
|
||||
/// 账号(HTTP、HTTPS、Socks5)
|
||||
/// </summary>
|
||||
public string Username;
|
||||
|
||||
/// <summary>
|
||||
/// 密码(HTTP、HTTPS、Socks5、SS、SSR)
|
||||
/// </summary>
|
||||
public string Password;
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID(VMess)
|
||||
/// </summary>
|
||||
public string UserID = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 额外 ID(VMess)
|
||||
/// </summary>
|
||||
public int AlterID = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式(SS、SSR、VMess)
|
||||
/// </summary>
|
||||
public string EncryptMethod;
|
||||
|
||||
/// <summary>
|
||||
/// 插件(SS)
|
||||
/// </summary>
|
||||
public string Plugin;
|
||||
|
||||
/// <summary>
|
||||
/// 插件参数(SS)
|
||||
/// </summary>
|
||||
public string PluginOption;
|
||||
|
||||
/// <summary>
|
||||
/// 协议(SSR)
|
||||
/// </summary>
|
||||
public string Protocol = Global.Protocols[0];
|
||||
|
||||
/// <summary>
|
||||
/// 协议参数(SSR)
|
||||
/// </summary>
|
||||
public string ProtocolParam;
|
||||
|
||||
/// <summary>
|
||||
/// 混淆(SSR)
|
||||
/// </summary>
|
||||
public string OBFS = Global.OBFSs[0];
|
||||
|
||||
/// <summary>
|
||||
/// 混淆参数(SSR)
|
||||
/// </summary>
|
||||
public string OBFSParam;
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议(VMess)
|
||||
/// </summary>
|
||||
public string TransferProtocol = Global.TransferProtocols[0];
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型(VMess)
|
||||
/// </summary>
|
||||
public string FakeType = Global.FakeTypes[0];
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名(VMess:HTTP、WebSocket、HTTP/2)
|
||||
/// </summary>
|
||||
public string Host = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 传输路径(VMess:WebSocket、HTTP/2)
|
||||
/// </summary>
|
||||
public string Path = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密方式(VMess)
|
||||
/// </summary>
|
||||
public string QUICSecure = Global.EncryptMethods.VMessQUIC[0];
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密密钥(VMess)
|
||||
/// </summary>
|
||||
public string QUICSecret = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// TLS 底层传输安全(VMess)
|
||||
/// </summary>
|
||||
public bool TLSSecure = false;
|
||||
|
||||
/// <summary>
|
||||
/// Mux 多路复用(VMess)
|
||||
/// </summary>
|
||||
public bool UseMux = true;
|
||||
|
||||
/// <summary>
|
||||
/// 延迟
|
||||
/// </summary>
|
||||
@@ -143,6 +46,8 @@ namespace Netch.Models
|
||||
/// </summary>
|
||||
public string Country;
|
||||
|
||||
public bool IsSocks5() => Type == "Socks5";
|
||||
|
||||
/// <summary>
|
||||
/// 获取备注
|
||||
/// </summary>
|
||||
@@ -186,7 +91,7 @@ namespace Netch.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
var destination = Utils.DNS.Lookup(Hostname);
|
||||
var destination = DNS.Lookup(Hostname);
|
||||
if (destination == null)
|
||||
{
|
||||
return Delay = -2;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Netch.Controllers;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.Models
|
||||
{
|
||||
public abstract class EncryptedProxy : Controller
|
||||
public abstract class ServerController : Controller
|
||||
{
|
||||
private int? _socks5Port;
|
||||
|
||||
@@ -28,5 +27,6 @@ namespace Netch.Controllers
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public abstract bool Start(Server server, Mode mode);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Netch.Models
|
||||
{
|
||||
|
||||
114
Netch/Models/WinFW/NetworkConnection.cs
Normal file
114
Netch/Models/WinFW/NetworkConnection.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using NETCONLib;
|
||||
|
||||
namespace WinFW
|
||||
{
|
||||
public class NetworkConnection : INetConnection, INetConnectionProps, INetSharingConfiguration
|
||||
{
|
||||
private readonly INetConnection _icsConn;
|
||||
|
||||
private readonly NetSharingManager _icsMgr;
|
||||
|
||||
public NetworkConnection(INetConnection icsConnection)
|
||||
{
|
||||
_icsMgr = new NetSharingManagerClass();
|
||||
_icsConn = icsConnection;
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
_icsConn.Connect();
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
_icsConn.Delete();
|
||||
}
|
||||
|
||||
public void Duplicate(string pszwDuplicateName, out INetConnection ppCon)
|
||||
{
|
||||
_icsConn.Duplicate(pszwDuplicateName, out ppCon);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_icsConn.Disconnect();
|
||||
}
|
||||
|
||||
public void GetProperties(IntPtr ppProps)
|
||||
{
|
||||
_icsConn.GetProperties(ppProps);
|
||||
}
|
||||
|
||||
public void Rename(string pszwNewName)
|
||||
{
|
||||
_icsConn.Rename(pszwNewName);
|
||||
}
|
||||
|
||||
public void GetUiObjectClassId(out Guid pclsid)
|
||||
{
|
||||
_icsConn.GetUiObjectClassId(out pclsid);
|
||||
}
|
||||
|
||||
public uint Characteristics => _icsMgr.NetConnectionProps[_icsConn].Characteristics;
|
||||
|
||||
public string DeviceName => _icsMgr.NetConnectionProps[_icsConn].DeviceName;
|
||||
|
||||
public string Guid => _icsMgr.NetConnectionProps[_icsConn].Guid;
|
||||
|
||||
public tagNETCON_MEDIATYPE MediaType => _icsMgr.NetConnectionProps[_icsConn].MediaType;
|
||||
|
||||
public string Name => _icsMgr.NetConnectionProps[_icsConn].Name;
|
||||
|
||||
public tagNETCON_STATUS Status => _icsMgr.NetConnectionProps[_icsConn].Status;
|
||||
|
||||
public INetSharingPortMapping AddPortMapping(string bstrName, byte ucIPProtocol, ushort usExternalPort,
|
||||
ushort usInternalPort, uint dwOptions, string bstrTargetNameOrIPAddress, tagICS_TARGETTYPE eTargetType)
|
||||
{
|
||||
return _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].AddPortMapping(bstrName,
|
||||
ucIPProtocol, usExternalPort, usInternalPort, dwOptions, bstrTargetNameOrIPAddress, eTargetType);
|
||||
}
|
||||
|
||||
public void DisableInternetFirewall() => _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].DisableInternetFirewall();
|
||||
|
||||
public void DisableSharing()
|
||||
{
|
||||
_icsMgr.INetSharingConfigurationForINetConnection[_icsConn].DisableSharing();
|
||||
}
|
||||
|
||||
public void EnableInternetFirewall()
|
||||
{
|
||||
_icsMgr.INetSharingConfigurationForINetConnection[_icsConn].EnableInternetFirewall();
|
||||
}
|
||||
|
||||
public void EnableSharing(tagSHARINGCONNECTIONTYPE Type)
|
||||
{
|
||||
_icsMgr.INetSharingConfigurationForINetConnection[_icsConn].EnableSharing(Type);
|
||||
}
|
||||
|
||||
public void RemovePortMapping(INetSharingPortMapping pMapping)
|
||||
{
|
||||
_icsMgr.INetSharingConfigurationForINetConnection[_icsConn].RemovePortMapping(pMapping);
|
||||
}
|
||||
|
||||
public bool InternetFirewallEnabled =>
|
||||
_icsMgr.INetSharingConfigurationForINetConnection[_icsConn]
|
||||
.InternetFirewallEnabled;
|
||||
|
||||
public INetSharingPortMappingCollection get_EnumPortMappings(tagSHARINGCONNECTION_ENUM_FLAGS Flags)
|
||||
{
|
||||
return _icsMgr.INetSharingConfigurationForINetConnection[_icsConn]
|
||||
.EnumPortMappings[Flags];
|
||||
}
|
||||
|
||||
public tagSHARINGCONNECTIONTYPE SharingConnectionType =>
|
||||
_icsMgr.INetSharingConfigurationForINetConnection[_icsConn].SharingConnectionType;
|
||||
|
||||
public bool SharingEnabled => _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].SharingEnabled;
|
||||
|
||||
public INetSharingConfiguration NetSharingConfigurationForINetConnection()
|
||||
{
|
||||
return _icsMgr.INetSharingConfigurationForINetConnection[_icsConn];
|
||||
}
|
||||
}
|
||||
}
|
||||
200
Netch/Models/WinFW/NetworkConnectionCollection.cs
Normal file
200
Netch/Models/WinFW/NetworkConnectionCollection.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NETCONLib;
|
||||
|
||||
namespace WinFW
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection that stores 'NetworkConnection' objects.
|
||||
/// </summary>
|
||||
public class NetworkConnectionCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of 'NetworkConnectionCollection'.
|
||||
/// </summary>
|
||||
public NetworkConnectionCollection()
|
||||
{
|
||||
NetSharingManager icsMgr = new NetSharingManagerClass();
|
||||
|
||||
foreach (var icsConn in icsMgr.EnumEveryConnection.Cast<INetConnection>())
|
||||
{
|
||||
Add(new NetworkConnection(icsConn));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the 'NetworkConnection' item at the specified index position.
|
||||
/// </summary>
|
||||
/// <param name="intIndex">
|
||||
/// The zero-based index of the entry to locate in the collection.
|
||||
/// </param>
|
||||
/// <value>
|
||||
/// The entry at the specified index of the collection.
|
||||
/// </value>
|
||||
public NetworkConnection this[int intIndex]
|
||||
{
|
||||
get => (NetworkConnection) List[intIndex];
|
||||
set => List[intIndex] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a 'NetworkConnection' item with the specified value to the 'NetworkConnectionCollection'
|
||||
/// </summary>
|
||||
/// <param name="conValue">
|
||||
/// The 'NetworkConnection' to add.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The index at which the new element was inserted.
|
||||
/// </returns>
|
||||
public int Add(NetworkConnection conValue)
|
||||
{
|
||||
return List.Add(conValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of an array at the end of this instance of 'NetworkConnectionCollection'.
|
||||
/// </summary>
|
||||
/// <param name="conValue">
|
||||
/// An array of 'NetworkConnection' objects to add to the collection.
|
||||
/// </param>
|
||||
public void AddRange(NetworkConnection[] conValue)
|
||||
{
|
||||
checked
|
||||
{
|
||||
foreach (var t in conValue)
|
||||
Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the contents of another 'NetworkConnectionCollection' at the end of this instance.
|
||||
/// </summary>
|
||||
/// <param name="conValue">
|
||||
/// A 'NetworkConnectionCollection' containing the objects to add to the collection.
|
||||
/// </param>
|
||||
public void AddRange(NetworkConnectionCollection conValue)
|
||||
{
|
||||
checked
|
||||
{
|
||||
for (var intCounter = 0; intCounter < conValue.Count; intCounter++) Add(conValue[intCounter]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the 'NetworkConnectionCollection' contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="conValue">
|
||||
/// The item to locate.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the item exists in the collection; false otherwise.
|
||||
/// </returns>
|
||||
public bool Contains(NetworkConnection conValue)
|
||||
{
|
||||
return List.Contains(conValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the 'NetworkConnectionCollection' values to a one-dimensional System.Array
|
||||
/// instance starting at the specified array index.
|
||||
/// </summary>
|
||||
/// <param name="conArray">
|
||||
/// The one-dimensional System.Array that represents the copy destination.
|
||||
/// </param>
|
||||
/// <param name="intIndex">
|
||||
/// The index in the array where copying begins.
|
||||
/// </param>
|
||||
public void CopyTo(NetworkConnection[] conArray, int intIndex)
|
||||
{
|
||||
List.CopyTo(conArray, intIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of a 'NetworkConnection' object in the collection.
|
||||
/// </summary>
|
||||
/// <param name="conValue">
|
||||
/// The 'NetworkConnection' object whose index will be retrieved.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If found, the index of the value; otherwise, -1.
|
||||
/// </returns>
|
||||
public int IndexOf(NetworkConnection conValue)
|
||||
{
|
||||
return List.IndexOf(conValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an existing 'NetworkConnection' into the collection at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="intIndex">
|
||||
/// The zero-based index where the new item should be inserted.
|
||||
/// </param>
|
||||
/// <param name="conValue">
|
||||
/// The item to insert.
|
||||
/// </param>
|
||||
public void Insert(int intIndex, NetworkConnection conValue)
|
||||
{
|
||||
List.Insert(intIndex, conValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can be used to iterate through
|
||||
/// the 'NetworkConnectionCollection'.
|
||||
/// </summary>
|
||||
public new ConnectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ConnectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specific item from the 'NetworkConnectionCollection'.
|
||||
/// </summary>
|
||||
/// <param name="conValue">
|
||||
/// The item to remove from the 'NetworkConnectionCollection'.
|
||||
/// </param>
|
||||
public void Remove(NetworkConnection conValue)
|
||||
{
|
||||
List.Remove(conValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A strongly typed enumerator for 'NetworkConnectionCollection'
|
||||
/// </summary>
|
||||
public class ConnectionEnumerator : IEnumerator
|
||||
{
|
||||
private readonly IEnumerator iEnBase;
|
||||
|
||||
private readonly IEnumerable iEnLocal;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerator constructor
|
||||
/// </summary>
|
||||
public ConnectionEnumerator(NetworkConnectionCollection conMappings)
|
||||
{
|
||||
iEnLocal = conMappings;
|
||||
iEnBase = iEnLocal.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element from the collection
|
||||
/// </summary>
|
||||
public object Current => iEnBase.Current;
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next element of the collection
|
||||
/// </summary>
|
||||
public bool MoveNext()
|
||||
{
|
||||
return iEnBase.MoveNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the enumerator to the first element in the collection
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
iEnBase.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public enum NameList : int
|
||||
{
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_ADDNAME,
|
||||
TYPE_BYPNAME,
|
||||
TYPE_CLRNAME
|
||||
}
|
||||
|
||||
public static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,7 +25,7 @@ namespace Netch
|
||||
/// <param name="index">适配器索引</param>
|
||||
/// <param name="metric">跃点数</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("bin\\NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateRoute")]
|
||||
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CreateRoute")]
|
||||
public static extern bool CreateRoute(string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
/// <summary>
|
||||
@@ -25,14 +37,14 @@ namespace Netch
|
||||
/// <param name="index">适配器索引</param>
|
||||
/// <param name="metric">跃点数</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("bin\\NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
|
||||
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
|
||||
public static extern bool DeleteRoute(string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 设置直连
|
||||
/// </summary>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("bin\\sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool SetDIRECT();
|
||||
|
||||
/// <summary>
|
||||
@@ -41,7 +53,7 @@ namespace Netch
|
||||
/// <param name="remote">地址</param>
|
||||
/// <param name="bypass">绕过</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("bin\\sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool SetGlobal([MarshalAs(UnmanagedType.LPTStr)] string remote, [MarshalAs(UnmanagedType.LPTStr)] string bypass);
|
||||
|
||||
/// <summary>
|
||||
@@ -49,17 +61,10 @@ namespace Netch
|
||||
/// </summary>
|
||||
/// <param name="remote">URL</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[DllImport("bin\\sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool SetURL([MarshalAs(UnmanagedType.LPTStr)] string remote);
|
||||
|
||||
public class Shadowsocks
|
||||
{
|
||||
[DllImport("bin\\shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Info(byte[] client, byte[] remote, byte[] passwd, byte[] method);
|
||||
[DllImport("bin\\shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Start();
|
||||
[DllImport("bin\\shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Stop();
|
||||
}
|
||||
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
|
||||
public static extern uint FlushDNSResolverCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace Netch
|
||||
{
|
||||
// 设置当前目录
|
||||
Directory.SetCurrentDirectory(Global.NetchDir);
|
||||
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ";" + Path.Combine(Global.NetchDir, "bin"), EnvironmentVariableTarget.Process);
|
||||
|
||||
// 预创建目录
|
||||
var directories = new[] {"mode", "data", "i18n", "logging"};
|
||||
@@ -66,9 +67,15 @@ namespace Netch
|
||||
}
|
||||
|
||||
Logging.Info($"版本: {UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}");
|
||||
Task.Run(() => { Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Application.ExecutablePath)}"); });
|
||||
Logging.Info("启动单实例");
|
||||
Task.Run(OnlyInstance.Server);
|
||||
Task.Run(() =>
|
||||
{
|
||||
Logging.Info($"主程序 SHA256: {Utils.Utils.SHA256CheckSum(Application.ExecutablePath)}");
|
||||
});
|
||||
Task.Run(() =>
|
||||
{
|
||||
Logging.Info("启动单实例");
|
||||
OnlyInstance.Server();
|
||||
});
|
||||
|
||||
// 绑定错误捕获
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
|
||||
@@ -54,6 +54,14 @@
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>false</Isolated>
|
||||
</COMReference>
|
||||
<COMReference Include="NETCONLib.dll">
|
||||
<Guid>{43E734CA-043D-4A70-9A2C-A8F254063D91}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -73,17 +81,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Web" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Forms\Server\Trojan.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Netch.Override
|
||||
{
|
||||
public class ToolStripProfessionalRender : System.Windows.Forms.ToolStripProfessionalRenderer
|
||||
{
|
||||
protected override void OnRenderToolStripBorder(System.Windows.Forms.ToolStripRenderEventArgs e)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,10 @@
|
||||
if %Configuration%==Release (
|
||||
:: Merge dlls
|
||||
%ILMergeConsolePath% %TargetDir%Netch.exe ^
|
||||
/out:%TargetDir%NetchMerged.exe ^
|
||||
%TargetDir%Dia2Lib.dll ^
|
||||
%TargetDir%Interop.NetFwTypeLib.dll ^
|
||||
%TargetDir%Interop.TaskScheduler.dll ^
|
||||
%TargetDir%MaxMind.Db.dll ^
|
||||
%TargetDir%MaxMind.GeoIP2.dll ^
|
||||
%TargetDir%Microsoft.Diagnostics.FastSerialization.dll ^
|
||||
%TargetDir%Microsoft.Diagnostics.Tracing.TraceEvent.dll ^
|
||||
%TargetDir%Microsoft.WindowsAPICodePack.dll ^
|
||||
%TargetDir%Microsoft.WindowsAPICodePack.Shell.dll ^
|
||||
%TargetDir%NetchLib.dll ^
|
||||
%TargetDir%Newtonsoft.Json.dll ^
|
||||
%TargetDir%OSExtensions.dll ^
|
||||
%TargetDir%System.Buffers.dll ^
|
||||
%TargetDir%System.Collections.Immutable.dll ^
|
||||
%TargetDir%System.Memory.dll ^
|
||||
%TargetDir%System.Net.IPNetwork.dll ^
|
||||
%TargetDir%System.Numerics.Vectors.dll ^
|
||||
%TargetDir%System.Reflection.Metadata.dll ^
|
||||
%TargetDir%System.Runtime.CompilerServices.Unsafe.dll ^
|
||||
%TargetDir%TraceReloggerLib.dll
|
||||
%ILMergeConsolePath% /wildcards /out:%TargetDir%NetchMerged.exe ^
|
||||
/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" ^
|
||||
/targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8" ^
|
||||
%TargetDir%Netch.exe ^
|
||||
%TargetDir%*.dll
|
||||
|
||||
DEL /f %TargetDir%*.dll >NUL 2>&1
|
||||
MOVE /Y %TargetDir%NetchMerged.exe %TargetDir%Netch.exe >NUL
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion(UpdateChecker.Version)]
|
||||
[assembly: AssemblyVersion(UpdateChecker.AssemblyVersion)]
|
||||
// [assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -33,11 +33,7 @@
|
||||
"Server": "服务器",
|
||||
"Import Servers From Clipboard": "从剪贴板导入服务器",
|
||||
"Import servers error!": "未找到可导入的链接!",
|
||||
"Add [Socks5] Server": "添加 [Socks5] 服务器",
|
||||
"Add [Shadowsocks] Server": "添加 [Shadowsocks] 服务器",
|
||||
"Add [ShadowsocksR] Server": "添加 [ShadowsocksR] 服务器",
|
||||
"Add [VMess] Server": "添加 [VMess] 服务器",
|
||||
"Add [Trojan] Server": "添加 [Trojan] 服务器",
|
||||
"Add [{0}] Server": "添加 [{0}] 服务器",
|
||||
"Netch is now minimized to the notification bar, double click this icon to restore.": "Netch 已最小化至通知栏,双击此图标恢复窗口。",
|
||||
"New version available": "发现新版本",
|
||||
"Already latest version": "已经是最新版本",
|
||||
@@ -100,6 +96,7 @@
|
||||
"Open Directory": "打开目录",
|
||||
|
||||
"About": "关于",
|
||||
"FAQ": "常见问题",
|
||||
"Telegram Channel": "Telegram 频道",
|
||||
"Sponsor": "赞助商",
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Forms.Server
|
||||
namespace Netch.ServerEx.Shadowsocks.Form
|
||||
{
|
||||
partial class Shadowsocks
|
||||
partial class ShadowsocksForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -28,7 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Shadowsocks));
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShadowsocksForm));
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.PluginOptionsTextBox = new System.Windows.Forms.TextBox();
|
||||
this.PluginOptionsLabel = new System.Windows.Forms.Label();
|
||||
@@ -215,7 +215,7 @@
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "Shadowsocks";
|
||||
this.Name = "ShadowsocksForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Shadowsocks";
|
||||
this.Load += new System.EventHandler(this.Shadowsocks_Load);
|
||||
59
Netch/ServerEx/Shadowsocks/Form/ShadowsocksForm.cs
Normal file
59
Netch/ServerEx/Shadowsocks/Form/ShadowsocksForm.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.ServerEx.Shadowsocks.Form
|
||||
{
|
||||
public partial class ShadowsocksForm : System.Windows.Forms.Form
|
||||
{
|
||||
private readonly Shadowsocks _server;
|
||||
|
||||
public ShadowsocksForm(Shadowsocks server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = server ?? new Shadowsocks();
|
||||
}
|
||||
|
||||
private void Shadowsocks_Load(object sender, EventArgs e)
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
EncryptMethodComboBox.Items.AddRange(SSGlobal.EncryptMethods.ToArray());
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
EncryptMethodComboBox.SelectedIndex = SSGlobal.EncryptMethods.IndexOf(_server.EncryptMethod);
|
||||
PluginTextBox.Text = _server.Plugin;
|
||||
PluginOptionsTextBox.Text = _server.PluginOption;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
Utils.Utils.DrawCenterComboBox(sender, e);
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ushort.TryParse(PortTextBox.Text, out var port)) return;
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "SS";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.EncryptMethod = EncryptMethodComboBox.Text;
|
||||
_server.Plugin = PluginTextBox.Text;
|
||||
_server.PluginOption = PluginOptionsTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
Global.Settings.Server.Add(_server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.SSD
|
||||
namespace Netch.ServerEx.Shadowsocks.Models.SSD
|
||||
{
|
||||
public class Main
|
||||
{
|
||||
@@ -37,6 +37,6 @@ namespace Netch.Models.SSD
|
||||
/// <summary>
|
||||
/// 服务器数组
|
||||
/// </summary>
|
||||
public List<Server> servers;
|
||||
public List<SSDServer> servers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Models.SSD
|
||||
namespace Netch.ServerEx.Shadowsocks.Models.SSD
|
||||
{
|
||||
public class Server
|
||||
public class SSDServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器地址
|
||||
@@ -37,4 +37,4 @@
|
||||
/// </summary>
|
||||
public string remarks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Models.SS
|
||||
namespace Netch.ServerEx.Shadowsocks.Models
|
||||
{
|
||||
public class ShadowsocksServer
|
||||
public class ShadowsocksConfig
|
||||
{
|
||||
public string server { get; set; }
|
||||
public int server_port { get; set; }
|
||||
96
Netch/ServerEx/Shadowsocks/SSController.cs
Normal file
96
Netch/ServerEx/Shadowsocks/SSController.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.ServerEx.Shadowsocks
|
||||
{
|
||||
public class SSController : ServerController
|
||||
{
|
||||
public SSController()
|
||||
{
|
||||
Name = "Shadowsocks";
|
||||
MainFile = "Shadowsocks.exe";
|
||||
}
|
||||
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
bool DllFlag()
|
||||
{
|
||||
return Global.Settings.BootShadowsocksFromDLL && (mode.Type == 0 || mode.Type == 1 || mode.Type == 2);
|
||||
}
|
||||
|
||||
var server = (Shadowsocks) s;
|
||||
//从DLL启动Shaowsocks
|
||||
if (DllFlag())
|
||||
{
|
||||
State = State.Starting;
|
||||
var client = Encoding.UTF8.GetBytes($"{LocalAddress}:{Socks5LocalPort}");
|
||||
var remote = Encoding.UTF8.GetBytes($"{server.Hostname}:{server.Port}");
|
||||
var passwd = Encoding.UTF8.GetBytes($"{server.Password}");
|
||||
var method = Encoding.UTF8.GetBytes($"{server.EncryptMethod}");
|
||||
if (!ShadowsocksDLL.Info(client, remote, passwd, method))
|
||||
{
|
||||
State = State.Stopped;
|
||||
Logging.Error("DLL SS INFO 设置失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS INFO 设置成功!");
|
||||
|
||||
if (!ShadowsocksDLL.Start())
|
||||
{
|
||||
State = State.Stopped;
|
||||
Logging.Error("DLL SS 启动失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.Info("DLL SS 启动成功!");
|
||||
State = State.Started;
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Argument
|
||||
|
||||
var argument = new StringBuilder();
|
||||
argument.Append(
|
||||
$"-s {server.Hostname} " +
|
||||
$"-p {server.Port} " +
|
||||
$"-b {LocalAddress} " +
|
||||
$"-l {Socks5LocalPort} " +
|
||||
$"-m {server.EncryptMethod} " +
|
||||
$"-k \"{server.Password}\" " +
|
||||
"-u ");
|
||||
if (!string.IsNullOrWhiteSpace(server.Plugin) && !string.IsNullOrWhiteSpace(server.PluginOption))
|
||||
argument.Append($"--plugin {server.Plugin} " +
|
||||
$"--plugin-opts \"{server.PluginOption}\"");
|
||||
if (mode.BypassChina)
|
||||
argument.Append(" --acl default.acl");
|
||||
|
||||
#endregion
|
||||
|
||||
return StartInstanceAuto(argument.ToString());
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
if (Instance == null)
|
||||
ShadowsocksDLL.Stop();
|
||||
else
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
|
||||
private class ShadowsocksDLL
|
||||
{
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Info(byte[] client, byte[] remote, byte[] passwd, byte[] method);
|
||||
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool Start();
|
||||
|
||||
[DllImport("shadowsocks-windows-dynamic", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
185
Netch/ServerEx/Shadowsocks/SSUtil.cs
Normal file
185
Netch/ServerEx/Shadowsocks/SSUtil.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Models;
|
||||
using Netch.ServerEx.Shadowsocks.Form;
|
||||
using Netch.ServerEx.Shadowsocks.Models.SSD;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.ServerEx.Shadowsocks
|
||||
{
|
||||
public class SSUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 1;
|
||||
public string TypeName { get; } = "SS";
|
||||
public string FullName { get; } = "Shadowsocks";
|
||||
|
||||
public string[] UriScheme { get; } = {"ss","ssd"};
|
||||
|
||||
public Server ParseJObject(JObject j)
|
||||
{
|
||||
return j.ToObject<Shadowsocks>();
|
||||
}
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksForm((Shadowsocks) s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
new ShadowsocksForm().ShowDialog();
|
||||
}
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
// ss://method:password@server:port#Remark
|
||||
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" + HttpUtility.UrlEncode(server.Remark);
|
||||
}
|
||||
|
||||
public ServerController GetController()
|
||||
{
|
||||
return new SSController();
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
if (text.StartsWith("ss://"))
|
||||
{
|
||||
return new[] {ParseSsUri(text)};
|
||||
}
|
||||
|
||||
if (text.StartsWith("ssd://"))
|
||||
{
|
||||
return ParseSsdUri(text);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseSsdUri(string s)
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)));
|
||||
|
||||
return json.servers.Select(server => new Shadowsocks
|
||||
{
|
||||
Remark = server.remarks,
|
||||
Hostname = server.server,
|
||||
Port = server.port != 0 ? server.port : json.port,
|
||||
Password = server.password ?? json.password,
|
||||
EncryptMethod = server.encryption ?? json.encryption,
|
||||
Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin,
|
||||
PluginOption = string.IsNullOrEmpty(json.plugin_options) ? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options : json.plugin_options
|
||||
})
|
||||
.Where(CheckServer);
|
||||
}
|
||||
|
||||
public Shadowsocks ParseSsUri(string text)
|
||||
{
|
||||
var data = new Shadowsocks();
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
try
|
||||
{
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var finder = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var match = finder.Match(text);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var plugins = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("plugin"));
|
||||
if (plugins != null)
|
||||
{
|
||||
var plugin = plugins.Substring(0, plugins.IndexOf(";", StringComparison.Ordinal));
|
||||
var pluginopts = plugins.Substring(plugins.IndexOf(";", StringComparison.Ordinal) + 1);
|
||||
switch (plugin)
|
||||
{
|
||||
case "obfs-local":
|
||||
case "simple-obfs":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=http;obfs-host=" + pluginopts;
|
||||
break;
|
||||
case "simple-obfs-tls":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=tls;obfs-host=" + pluginopts;
|
||||
break;
|
||||
}
|
||||
|
||||
data.Plugin = plugin;
|
||||
data.PluginOption = pluginopts;
|
||||
}
|
||||
|
||||
text = match.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
if (text.Contains("@"))
|
||||
{
|
||||
var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success) throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
|
||||
var base64 = ShareLink.URLSafeBase64Decode(match.Groups["base64"].Value);
|
||||
match = parser.Match(base64);
|
||||
if (!match.Success) throw new FormatException();
|
||||
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parser = new Regex(@"^((?<method>.+?):(?<password>.+)@(?<server>.+):(?<port>\d+))");
|
||||
var match = parser.Match(ShareLink.URLSafeBase64Decode(text.Replace("ss://", "")));
|
||||
if (!match.Success) throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
|
||||
return CheckServer(data) ? data : null;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Netch/ServerEx/Shadowsocks/Shadowsocks.cs
Normal file
62
Netch/ServerEx/Shadowsocks/Shadowsocks.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.ServerEx.Shadowsocks
|
||||
{
|
||||
public class Shadowsocks : Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod { get; set; } = SSGlobal.EncryptMethods[0];
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
public string Plugin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件参数
|
||||
/// </summary>
|
||||
public string PluginOption { get; set; }
|
||||
|
||||
public Shadowsocks()
|
||||
{
|
||||
Type = "SS";
|
||||
}
|
||||
}
|
||||
|
||||
public static class SSGlobal
|
||||
{
|
||||
/// <summary>
|
||||
/// SS 加密列表
|
||||
/// </summary>
|
||||
public static readonly List<string> EncryptMethods = new List<string>
|
||||
{
|
||||
"rc4-md5",
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"bf-cfb",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Forms.Server
|
||||
namespace Netch.ServerEx.ShadowsocksR.Form
|
||||
{
|
||||
partial class ShadowsocksR
|
||||
partial class ShadowsocksRForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -28,7 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShadowsocksR));
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShadowsocksRForm));
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.OBFSParamLabel = new System.Windows.Forms.Label();
|
||||
this.OBFSOptionParamTextBox = new System.Windows.Forms.TextBox();
|
||||
@@ -263,7 +263,7 @@
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "ShadowsocksR";
|
||||
this.Name = "ShadowsocksRForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "ShadowsocksR";
|
||||
this.Load += new System.EventHandler(this.ShadowsocksR_Load);
|
||||
65
Netch/ServerEx/ShadowsocksR/Form/ShadowsocksRForm.cs
Normal file
65
Netch/ServerEx/ShadowsocksR/Form/ShadowsocksRForm.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.ServerEx.ShadowsocksR.Form
|
||||
{
|
||||
public partial class ShadowsocksRForm : System.Windows.Forms.Form
|
||||
{
|
||||
private readonly ShadowsocksR _server;
|
||||
|
||||
public ShadowsocksRForm(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = (ShadowsocksR) (server ?? new ShadowsocksR());
|
||||
}
|
||||
|
||||
private void ShadowsocksR_Load(object sender, EventArgs e)
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
EncryptMethodComboBox.Items.AddRange(SSRGlobal.EncryptMethods.ToArray());
|
||||
ProtocolComboBox.Items.AddRange(SSRGlobal.Protocols.ToArray());
|
||||
OBFSComboBox.Items.AddRange(SSRGlobal.OBFSs.ToArray());
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
EncryptMethodComboBox.SelectedIndex = SSRGlobal.EncryptMethods.IndexOf(_server.EncryptMethod);
|
||||
ProtocolComboBox.SelectedIndex = SSRGlobal.Protocols.IndexOf(_server.Protocol);
|
||||
ProtocolParamTextBox.Text = _server.ProtocolParam;
|
||||
OBFSComboBox.SelectedIndex = SSRGlobal.OBFSs.IndexOf(_server.OBFS);
|
||||
OBFSOptionParamTextBox.Text = _server.OBFSParam;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
Utils.Utils.DrawCenterComboBox(sender, e);
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ushort.TryParse(PortTextBox.Text, out var port)) return;
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "SSR";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.EncryptMethod = EncryptMethodComboBox.Text;
|
||||
_server.Protocol = ProtocolComboBox.Text;
|
||||
_server.ProtocolParam = ProtocolParamTextBox.Text;
|
||||
_server.OBFS = OBFSComboBox.Text;
|
||||
_server.OBFSParam = OBFSOptionParamTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
Global.Settings.Server.Add(_server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.ServerEx.ShadowsocksR
|
||||
{
|
||||
public class SSRController : EncryptedProxy
|
||||
public class SSRController : ServerController
|
||||
{
|
||||
public SSRController()
|
||||
{
|
||||
Name = "ShadowsocksR";
|
||||
MainFile = "ShadowsocksR.exe";
|
||||
StartedKeywords.Add("listening at");
|
||||
StoppedKeywords.AddRange(new[] {"Invalid config path", "usage"});
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
|
||||
#region Argument
|
||||
|
||||
var argument = new StringBuilder();
|
||||
144
Netch/ServerEx/ShadowsocksR/SSRUtil.cs
Normal file
144
Netch/ServerEx/ShadowsocksR/SSRUtil.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Netch.Models;
|
||||
using Netch.ServerEx.ShadowsocksR.Form;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.ServerEx.ShadowsocksR
|
||||
{
|
||||
public class SSRUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 1;
|
||||
public string TypeName { get; } = "SSR";
|
||||
public string FullName { get; } = "ShadowsocksR";
|
||||
|
||||
public string[] UriScheme { get; } = {"ssr"};
|
||||
|
||||
public Server ParseJObject(JObject j)
|
||||
{
|
||||
return j.ToObject<ShadowsocksR>();
|
||||
}
|
||||
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksRForm(s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
new ShadowsocksRForm().ShowDialog();
|
||||
}
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
|
||||
// https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
|
||||
// ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
||||
var paraStr = $"/?obfsparam={ShareLink.URLSafeBase64Encode(server.OBFSParam)}&protoparam={ShareLink.URLSafeBase64Encode(server.ProtocolParam)}&remarks={ShareLink.URLSafeBase64Encode(server.Remark)}";
|
||||
return "ssr://" + ShareLink.URLSafeBase64Encode($"{server.Hostname}:{server.Port}:{server.Protocol}:{server.EncryptMethod}:{server.OBFS}:{ShareLink.URLSafeBase64Encode(server.Password)}{paraStr}");
|
||||
}
|
||||
|
||||
public ServerController GetController()
|
||||
{
|
||||
return new SSRController();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSR链接解析器
|
||||
/// Copy From https://github.com/HMBSbige/ShadowsocksR-Windows/blob/d9dc8d032a6e04c14b9dc6c8f673c9cc5aa9f607/shadowsocks-csharp/Model/Server.cs#L428
|
||||
/// Thx :D
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
// ssr://host:port:protocol:method:obfs:base64pass/?obfsparam=base64&remarks=base64&group=base64&udpport=0&uot=1
|
||||
var ssr = Regex.Match(text, "ssr://([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase);
|
||||
if (!ssr.Success)
|
||||
throw new FormatException();
|
||||
|
||||
var data = ShareLink.URLSafeBase64Decode(ssr.Groups[1].Value);
|
||||
var paramsDict = new Dictionary<string, string>();
|
||||
|
||||
var paramStartPos = data.IndexOf("?", StringComparison.Ordinal);
|
||||
if (paramStartPos > 0)
|
||||
{
|
||||
paramsDict = ShareLink.ParseParam(data.Substring(paramStartPos + 1));
|
||||
data = data.Substring(0, paramStartPos);
|
||||
}
|
||||
|
||||
if (data.IndexOf("/", StringComparison.Ordinal) >= 0) data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal));
|
||||
|
||||
var urlFinder = new Regex("^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)");
|
||||
var match = urlFinder.Match(data);
|
||||
|
||||
if (match == null || !match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
var serverAddr = match.Groups[1].Value;
|
||||
var serverPort = ushort.Parse(match.Groups[2].Value);
|
||||
var protocol = match.Groups[3].Value.Length == 0 ? "origin" : match.Groups[3].Value;
|
||||
protocol = protocol.Replace("_compatible", "");
|
||||
var method = match.Groups[4].Value;
|
||||
var obfs = match.Groups[5].Value.Length == 0 ? "plain" : match.Groups[5].Value;
|
||||
obfs = obfs.Replace("_compatible", "");
|
||||
var password = ShareLink.URLSafeBase64Decode(match.Groups[6].Value);
|
||||
var protocolParam = "";
|
||||
var obfsParam = "";
|
||||
var remarks = "";
|
||||
|
||||
if (paramsDict.ContainsKey("protoparam")) protocolParam = ShareLink.URLSafeBase64Decode(paramsDict["protoparam"]);
|
||||
|
||||
if (paramsDict.ContainsKey("obfsparam")) obfsParam = ShareLink.URLSafeBase64Decode(paramsDict["obfsparam"]);
|
||||
|
||||
if (paramsDict.ContainsKey("remarks")) remarks = ShareLink.URLSafeBase64Decode(paramsDict["remarks"]);
|
||||
|
||||
var group = paramsDict.ContainsKey("group") ? ShareLink.URLSafeBase64Decode(paramsDict["group"]) : string.Empty;
|
||||
|
||||
return new[]
|
||||
{
|
||||
new ShadowsocksR
|
||||
{
|
||||
Hostname = serverAddr,
|
||||
Port = serverPort,
|
||||
Protocol = protocol,
|
||||
EncryptMethod = method,
|
||||
OBFS = obfs,
|
||||
Password = password,
|
||||
ProtocolParam = protocolParam,
|
||||
OBFSParam = obfsParam,
|
||||
Remark = remarks,
|
||||
Group = group
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (ShadowsocksR) s;
|
||||
if (!SSRGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 加密方式:{server.EncryptMethod}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSRGlobal.Protocols.Contains(server.Protocol))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 协议:{server.Protocol}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSRGlobal.OBFSs.Contains(server.OBFS))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 混淆:{server.OBFS}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Netch/ServerEx/ShadowsocksR/ShadowsocksR.cs
Normal file
100
Netch/ServerEx/ShadowsocksR/ShadowsocksR.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.ServerEx.ShadowsocksR
|
||||
{
|
||||
public class ShadowsocksR : Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod { get; set; } = SSRGlobal.EncryptMethods[0];
|
||||
|
||||
/// <summary>
|
||||
/// 混淆
|
||||
/// </summary>
|
||||
public string OBFS { get; set; } = SSRGlobal.OBFSs[0];
|
||||
|
||||
/// <summary>
|
||||
/// 混淆参数
|
||||
/// </summary>
|
||||
public string OBFSParam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 协议
|
||||
/// </summary>
|
||||
public string Protocol { get; set; } = SSRGlobal.Protocols[0];
|
||||
|
||||
/// <summary>
|
||||
/// 协议参数
|
||||
/// </summary>
|
||||
public string ProtocolParam { get; set; }
|
||||
|
||||
public ShadowsocksR()
|
||||
{
|
||||
Type = "SSR";
|
||||
}
|
||||
}
|
||||
|
||||
public class SSRGlobal
|
||||
{
|
||||
/// <summary>
|
||||
/// SSR 协议列表
|
||||
/// </summary>
|
||||
public static readonly List<string> Protocols = new List<string>
|
||||
{
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_md5",
|
||||
"auth_aes128_sha1",
|
||||
"auth_chain_a"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// SSR 混淆列表
|
||||
/// </summary>
|
||||
public static readonly List<string> OBFSs = new List<string>
|
||||
{
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"tls1.2_ticket_auth"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// SS/SSR 加密方式
|
||||
/// </summary>
|
||||
public static readonly List<string> EncryptMethods = new List<string>
|
||||
{
|
||||
"none",
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Forms.Server
|
||||
namespace Netch.ServerEx.Socks5.Form
|
||||
{
|
||||
partial class Socks5
|
||||
partial class Socks5Form
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -28,7 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Socks5));
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Socks5Form));
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.PasswordLabel = new System.Windows.Forms.Label();
|
||||
this.UsernameTextBox = new System.Windows.Forms.TextBox();
|
||||
@@ -170,10 +170,10 @@
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "Socks5";
|
||||
this.Name = "Socks5Form";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Socks5";
|
||||
this.Load += new System.EventHandler(this.Shadowsocks_Load);
|
||||
this.Load += new System.EventHandler(this.Socks5_Load);
|
||||
this.ConfigurationGroupBox.ResumeLayout(false);
|
||||
this.ConfigurationGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
47
Netch/ServerEx/Socks5/Form/Socks5Form.cs
Normal file
47
Netch/ServerEx/Socks5/Form/Socks5Form.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.ServerEx.Socks5.Form
|
||||
{
|
||||
public partial class Socks5Form : System.Windows.Forms.Form
|
||||
{
|
||||
private readonly Socks5 _server;
|
||||
|
||||
public Socks5Form(Models.Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = (Socks5) (server ?? new Socks5());
|
||||
}
|
||||
|
||||
private void Socks5_Load(object sender, EventArgs e)
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
UsernameTextBox.Text = _server.Username;
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ushort.TryParse(PortTextBox.Text, out var port)) return;
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "Socks5";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Username = UsernameTextBox.Text;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
Global.Settings.Server.Add(_server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Netch/ServerEx/Socks5/S5Util.cs
Normal file
81
Netch/ServerEx/Socks5/S5Util.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Netch.Models;
|
||||
using Netch.ServerEx.Socks5.Form;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.ServerEx.Socks5
|
||||
{
|
||||
public class S5Util : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 0;
|
||||
public string TypeName { get; } = "Socks5";
|
||||
public string FullName { get; } = "Socks5";
|
||||
|
||||
public string[] UriScheme { get; } = { };
|
||||
|
||||
public Server ParseJObject(JObject j)
|
||||
{
|
||||
return j.ToObject<Socks5>();
|
||||
}
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new Socks5Form(s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
new Socks5Form().ShowDialog();
|
||||
}
|
||||
|
||||
public string GetShareLink(Server server)
|
||||
{
|
||||
// https://t.me/socks?server=1.1.1.1&port=443
|
||||
return $"https://t.me/socks?server={server.Hostname}&port={server.Port}";
|
||||
}
|
||||
|
||||
public ServerController GetController()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
var dict = text
|
||||
.Replace("tg://socks?", "")
|
||||
.Replace("https://t.me/socks?", "")
|
||||
.Split('&')
|
||||
.Select(str => str.Split('='))
|
||||
.ToDictionary(splited => splited[0], splited => splited[1]);
|
||||
|
||||
if (!dict.ContainsKey("server") || !dict.ContainsKey("port"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = new Socks5
|
||||
{
|
||||
Hostname = dict["server"],
|
||||
Port = int.Parse(dict["port"])
|
||||
};
|
||||
|
||||
if (dict.ContainsKey("user") && !string.IsNullOrWhiteSpace(dict["user"]))
|
||||
{
|
||||
data.Username = dict["user"];
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("pass") && !string.IsNullOrWhiteSpace(dict["pass"]))
|
||||
{
|
||||
data.Password = dict["pass"];
|
||||
}
|
||||
|
||||
return new[] {data};
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Netch/ServerEx/Socks5/Socks5.cs
Normal file
22
Netch/ServerEx/Socks5/Socks5.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.ServerEx.Socks5
|
||||
{
|
||||
public class Socks5 : Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password;
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
public string Username;
|
||||
|
||||
public Socks5()
|
||||
{
|
||||
Type = "Socks5";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Forms.Server
|
||||
namespace Netch.ServerEx.Trojan.Form
|
||||
{
|
||||
partial class Trojan
|
||||
partial class TrojanForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -28,7 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Trojan));
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TrojanForm));
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.PasswordTextBox = new System.Windows.Forms.TextBox();
|
||||
this.PasswordLabel = new System.Windows.Forms.Label();
|
||||
@@ -149,10 +149,10 @@
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "Trojan";
|
||||
this.Name = "TrojanForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Trojan";
|
||||
this.Load += new System.EventHandler(this.Trojan_Load);
|
||||
this.Load += new System.EventHandler(this.TrojanForm_Load);
|
||||
this.ConfigurationGroupBox.ResumeLayout(false);
|
||||
this.ConfigurationGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
52
Netch/ServerEx/Trojan/Form/TrojanForm.cs
Normal file
52
Netch/ServerEx/Trojan/Form/TrojanForm.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.ServerEx.Trojan.Form
|
||||
{
|
||||
public partial class TrojanForm : System.Windows.Forms.Form
|
||||
{
|
||||
private readonly Trojan _server;
|
||||
|
||||
public TrojanForm(Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = (Trojan) (server ?? new Trojan());
|
||||
}
|
||||
|
||||
private void TrojanForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
PasswordTextBox.Text = _server.Password;
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
Utils.Utils.DrawCenterComboBox(sender, e);
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ushort.TryParse(PortTextBox.Text, out var port)) return;
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "Trojan";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.Password = PasswordTextBox.Text;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
Global.Settings.Server.Add(_server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models
|
||||
namespace Netch.ServerEx.Trojan.Models
|
||||
{
|
||||
public class Trojan
|
||||
public class TrojanConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动类型
|
||||
@@ -55,11 +51,13 @@ namespace Netch.Models
|
||||
public string cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
|
||||
public string cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384";
|
||||
public string sni = string.Empty;
|
||||
public List<string> alpn = new List<string>()
|
||||
|
||||
public List<string> alpn = new List<string>
|
||||
{
|
||||
"h2",
|
||||
"http/1.1"
|
||||
};
|
||||
|
||||
public bool reuse_session = true;
|
||||
public bool session_ticket = true;
|
||||
public string curves = "";
|
||||
@@ -73,4 +71,4 @@ namespace Netch.Models
|
||||
public bool fast_open = true;
|
||||
public int fast_open_qlen = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Netch/ServerEx/Trojan/Trojan.cs
Normal file
22
Netch/ServerEx/Trojan/Trojan.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.ServerEx.Trojan
|
||||
{
|
||||
public class Trojan : Server
|
||||
{
|
||||
public Trojan()
|
||||
{
|
||||
Type = "Trojan";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Netch.ServerEx.Trojan.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.ServerEx.Trojan
|
||||
{
|
||||
public class TrojanController : EncryptedProxy
|
||||
public class TrojanController : ServerController
|
||||
{
|
||||
public TrojanController()
|
||||
{
|
||||
@@ -18,9 +16,10 @@ namespace Netch.Controllers
|
||||
StoppedKeywords.Add("exiting");
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new Trojan
|
||||
var server = (Trojan) s;
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new TrojanConfig
|
||||
{
|
||||
local_addr = LocalAddress,
|
||||
local_port = Socks5LocalPort,
|
||||
102
Netch/ServerEx/Trojan/TrojanUtil.cs
Normal file
102
Netch/ServerEx/Trojan/TrojanUtil.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Models;
|
||||
using Netch.ServerEx.Trojan.Form;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.ServerEx.Trojan
|
||||
{
|
||||
public class TrojanUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 2;
|
||||
public string TypeName { get; } = "Trojan";
|
||||
public string FullName { get; } = "Trojan";
|
||||
|
||||
public string[] UriScheme { get; } = {"trojan"};
|
||||
|
||||
public Server ParseJObject(JObject j)
|
||||
{
|
||||
return j.ToObject<Trojan>();
|
||||
}
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new TrojanForm(s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
new TrojanForm().ShowDialog();
|
||||
}
|
||||
|
||||
public string GetShareLink(Server server)
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
public ServerController GetController()
|
||||
{
|
||||
return new TrojanController();
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
var data = new Trojan();
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
try
|
||||
{
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var reg = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var regmatch = reg.Match(text);
|
||||
|
||||
if (regmatch.Success)
|
||||
{
|
||||
var peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("peer"));
|
||||
|
||||
if (peer != null)
|
||||
data.Host = peer;
|
||||
|
||||
text = regmatch.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
var finder = new Regex(@"^trojan://(?<psk>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
data.Password = match.Groups["psk"].Value;
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
|
||||
return new[] {data};
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Netch.Forms.Server
|
||||
namespace Netch.ServerEx.VMess.Form
|
||||
{
|
||||
partial class VMess
|
||||
partial class VMessForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
@@ -28,7 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VMess));
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VMessForm));
|
||||
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.UseMuxCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.TLSSecureCheckBox = new System.Windows.Forms.CheckBox();
|
||||
@@ -382,7 +382,7 @@
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 6, 4, 6);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "VMess";
|
||||
this.Name = "VMessForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "VMess";
|
||||
this.Load += new System.EventHandler(this.VMess_Load);
|
||||
80
Netch/ServerEx/VMess/Form/VMessForm.cs
Normal file
80
Netch/ServerEx/VMess/Form/VMessForm.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.ServerEx.VMess.Form
|
||||
{
|
||||
public partial class VMessForm : System.Windows.Forms.Form
|
||||
{
|
||||
private static VMess _server;
|
||||
|
||||
public VMessForm(Server server = default)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_server = (VMess) server ?? new VMess();
|
||||
}
|
||||
|
||||
private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
Utils.Utils.DrawCenterComboBox(sender, e);
|
||||
}
|
||||
|
||||
private void VMess_Load(object sender, EventArgs e)
|
||||
{
|
||||
i18N.TranslateForm(this);
|
||||
|
||||
EncryptMethodComboBox.Items.AddRange(VMessGlobal.EncryptMethods.ToArray());
|
||||
TransferProtocolComboBox.Items.AddRange(VMessGlobal.TransferProtocols.ToArray());
|
||||
FakeTypeComboBox.Items.AddRange(VMessGlobal.FakeTypes.ToArray());
|
||||
QUICSecurityComboBox.Items.AddRange(VMessGlobal.QUIC.ToArray());
|
||||
|
||||
|
||||
RemarkTextBox.Text = _server.Remark;
|
||||
AddressTextBox.Text = _server.Hostname;
|
||||
PortTextBox.Text = _server.Port.ToString();
|
||||
UserIDTextBox.Text = _server.UserID;
|
||||
AlterIDTextBox.Text = _server.AlterID.ToString();
|
||||
EncryptMethodComboBox.SelectedIndex = VMessGlobal.EncryptMethods.IndexOf(_server.EncryptMethod);
|
||||
TransferProtocolComboBox.SelectedIndex = VMessGlobal.TransferProtocols.IndexOf(_server.TransferProtocol);
|
||||
FakeTypeComboBox.SelectedIndex = VMessGlobal.FakeTypes.IndexOf(_server.FakeType);
|
||||
HostTextBox.Text = _server.Host;
|
||||
PathTextBox.Text = _server.Path;
|
||||
QUICSecurityComboBox.SelectedIndex = VMessGlobal.QUIC.IndexOf(_server.QUICSecure);
|
||||
QUICSecretTextBox.Text = _server.QUICSecret;
|
||||
TLSSecureCheckBox.Checked = _server.TLSSecure;
|
||||
UseMuxCheckBox.Checked = _server.UseMux;
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ushort.TryParse(PortTextBox.Text, out var port)) return;
|
||||
|
||||
if (!int.TryParse(AlterIDTextBox.Text, out var alterId)) return;
|
||||
|
||||
_server.Remark = RemarkTextBox.Text;
|
||||
_server.Type = "VMess";
|
||||
_server.Hostname = AddressTextBox.Text;
|
||||
_server.Port = port;
|
||||
_server.UserID = UserIDTextBox.Text;
|
||||
_server.AlterID = alterId;
|
||||
_server.EncryptMethod = EncryptMethodComboBox.Text;
|
||||
_server.TransferProtocol = TransferProtocolComboBox.Text;
|
||||
_server.FakeType = FakeTypeComboBox.Text;
|
||||
_server.Host = HostTextBox.Text;
|
||||
_server.Path = PathTextBox.Text;
|
||||
_server.QUICSecure = QUICSecurityComboBox.Text;
|
||||
_server.QUICSecret = QUICSecretTextBox.Text;
|
||||
_server.TLSSecure = TLSSecureCheckBox.Checked;
|
||||
_server.UseMux = UseMuxCheckBox.Checked;
|
||||
_server.Country = null;
|
||||
|
||||
if (Global.Settings.Server.IndexOf(_server) == -1)
|
||||
Global.Settings.Server.Add(_server);
|
||||
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Information
|
||||
namespace Netch.ServerEx.VMess.Models
|
||||
{
|
||||
public class VMess
|
||||
public class VMessConfig
|
||||
{
|
||||
public class InboundSettings
|
||||
{
|
||||
@@ -203,4 +203,4 @@ namespace Netch.Models.Information
|
||||
public Routing routing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace Netch.Models
|
||||
namespace Netch.ServerEx.VMess.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用 v2rayN 定义的 VMess 链接格式
|
||||
/// </summary>
|
||||
public class VMess
|
||||
public class VMessJObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Mux Class
|
||||
@@ -73,4 +73,4 @@
|
||||
/// </summary>
|
||||
public Mux mux;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
Netch/ServerEx/VMess/VMess.cs
Normal file
118
Netch/ServerEx/VMess/VMess.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
|
||||
namespace Netch.ServerEx.VMess
|
||||
{
|
||||
public class VMess : Server
|
||||
{
|
||||
public VMess()
|
||||
{
|
||||
Type = "VMess";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID
|
||||
/// </summary>
|
||||
public string UserID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 额外 ID
|
||||
/// </summary>
|
||||
public int AlterID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
public string EncryptMethod { get; set; } = VMessGlobal.EncryptMethods[0];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议
|
||||
/// </summary>
|
||||
public string TransferProtocol { get; set; } = VMessGlobal.TransferProtocols[0];
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public string FakeType { get; set; } = VMessGlobal.FakeTypes[0];
|
||||
|
||||
/// <summary>
|
||||
/// QUIC
|
||||
/// </summary>
|
||||
public string QUIC { get; set; } = VMessGlobal.QUIC[0];
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密方式
|
||||
/// </summary>
|
||||
public string QUICSecure { get; set; } = VMessGlobal.QUIC[0];
|
||||
|
||||
/// <summary>
|
||||
/// QUIC 加密密钥
|
||||
/// </summary>
|
||||
public string QUICSecret { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// TLS 底层传输安全
|
||||
/// </summary>
|
||||
public bool TLSSecure { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Mux 多路复用
|
||||
/// </summary>
|
||||
public bool UseMux { get; set; } = true;
|
||||
}
|
||||
|
||||
public class VMessGlobal
|
||||
{
|
||||
public static readonly List<string> EncryptMethods = new List<string>
|
||||
{
|
||||
"auto",
|
||||
"none",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305"
|
||||
};
|
||||
|
||||
public static readonly List<string> QUIC = new List<string>
|
||||
{
|
||||
"none",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// V2Ray 传输协议
|
||||
/// </summary>
|
||||
public static readonly List<string> TransferProtocols = new List<string>
|
||||
{
|
||||
"tcp",
|
||||
"kcp",
|
||||
"ws",
|
||||
"h2",
|
||||
"quic"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// V2Ray 伪装类型
|
||||
/// </summary>
|
||||
public static readonly List<string> FakeTypes = new List<string>
|
||||
{
|
||||
"none",
|
||||
"http",
|
||||
"srtp",
|
||||
"utp",
|
||||
"wechat-video",
|
||||
"dtls",
|
||||
"wireguard"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Netch.Models;
|
||||
using Netch.Utils;
|
||||
using Netch.ServerEx.VMess.Models;
|
||||
using Newtonsoft.Json;
|
||||
using VMess = Netch.Models.Information.VMess;
|
||||
|
||||
namespace Netch.Controllers
|
||||
namespace Netch.ServerEx.VMess
|
||||
{
|
||||
public class VMessController : EncryptedProxy
|
||||
public class VMessController : ServerController
|
||||
{
|
||||
public VMessController()
|
||||
{
|
||||
@@ -18,34 +16,35 @@ namespace Netch.Controllers
|
||||
StoppedKeywords.AddRange(new[] {"config file not readable", "failed to"});
|
||||
}
|
||||
|
||||
public override bool Start(Server server, Mode mode)
|
||||
public override bool Start(Server s, Mode mode)
|
||||
{
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new VMess.Config
|
||||
var server = (VMess) s;
|
||||
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new VMessConfig.Config()
|
||||
{
|
||||
inbounds = new List<VMess.Inbounds>
|
||||
inbounds = new List<VMessConfig.Inbounds>
|
||||
{
|
||||
new VMess.Inbounds
|
||||
new VMessConfig.Inbounds
|
||||
{
|
||||
settings = new VMess.InboundSettings(),
|
||||
settings = new VMessConfig.InboundSettings(),
|
||||
port = Socks5LocalPort,
|
||||
listen = LocalAddress
|
||||
}
|
||||
},
|
||||
outbounds = new List<VMess.Outbounds>
|
||||
outbounds = new List<VMessConfig.Outbounds>
|
||||
{
|
||||
new VMess.Outbounds
|
||||
new VMessConfig.Outbounds
|
||||
{
|
||||
settings = new VMess.OutboundSettings
|
||||
settings = new VMessConfig.OutboundSettings
|
||||
{
|
||||
vnext = new List<VMess.VNext>
|
||||
vnext = new List<VMessConfig.VNext>
|
||||
{
|
||||
new VMess.VNext
|
||||
new VMessConfig.VNext
|
||||
{
|
||||
address = server.Hostname,
|
||||
port = server.Port,
|
||||
users = new List<VMess.User>
|
||||
users = new List<VMessConfig.User>
|
||||
{
|
||||
new VMess.User
|
||||
new VMessConfig.User
|
||||
{
|
||||
id = server.UserID,
|
||||
alterId = server.AlterID,
|
||||
@@ -55,30 +54,30 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
},
|
||||
streamSettings = new VMess.StreamSettings
|
||||
streamSettings = new VMessConfig.StreamSettings
|
||||
{
|
||||
network = server.TransferProtocol,
|
||||
security = server.TLSSecure ? "tls" : string.Empty,
|
||||
wsSettings = server.TransferProtocol == "ws"
|
||||
? new VMess.WebSocketSettings
|
||||
? new VMessConfig.WebSocketSettings
|
||||
{
|
||||
path = server.Path == string.Empty ? "/" : server.Path,
|
||||
headers = new VMess.WSHeaders
|
||||
headers = new VMessConfig.WSHeaders
|
||||
{
|
||||
Host = server.Host == string.Empty ? server.Hostname : server.Host
|
||||
}
|
||||
}
|
||||
: null,
|
||||
tcpSettings = server.FakeType == "http"
|
||||
? new VMess.TCPSettings
|
||||
? new VMessConfig.TCPSettings
|
||||
{
|
||||
header = new VMess.TCPHeaders
|
||||
header = new VMessConfig.TCPHeaders
|
||||
{
|
||||
type = server.FakeType,
|
||||
request = new VMess.TCPRequest
|
||||
request = new VMessConfig.TCPRequest
|
||||
{
|
||||
path = server.Path == string.Empty ? "/" : server.Path,
|
||||
headers = new VMess.TCPRequestHeaders
|
||||
headers = new VMessConfig.TCPRequestHeaders
|
||||
{
|
||||
Host = server.Host == string.Empty ? server.Hostname : server.Host
|
||||
}
|
||||
@@ -87,61 +86,61 @@ namespace Netch.Controllers
|
||||
}
|
||||
: null,
|
||||
kcpSettings = server.TransferProtocol == "kcp"
|
||||
? new VMess.KCPSettings
|
||||
? new VMessConfig.KCPSettings
|
||||
{
|
||||
header = new VMess.TCPHeaders
|
||||
header = new VMessConfig.TCPHeaders
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
}
|
||||
: null,
|
||||
quicSettings = server.TransferProtocol == "quic"
|
||||
? new VMess.QUICSettings
|
||||
? new VMessConfig.QUICSettings
|
||||
{
|
||||
security = server.QUICSecure,
|
||||
key = server.QUICSecret,
|
||||
header = new VMess.TCPHeaders
|
||||
header = new VMessConfig.TCPHeaders
|
||||
{
|
||||
type = server.FakeType
|
||||
}
|
||||
}
|
||||
: null,
|
||||
httpSettings = server.TransferProtocol == "h2"
|
||||
? new VMess.HTTPSettings
|
||||
? new VMessConfig.HTTPSettings
|
||||
{
|
||||
host = server.Host == "" ? server.Hostname : server.Host,
|
||||
path = server.Path == "" ? "/" : server.Path
|
||||
}
|
||||
: null,
|
||||
tlsSettings = new VMess.TLSSettings
|
||||
tlsSettings = new VMessConfig.TLSSettings
|
||||
{
|
||||
allowInsecure = true,
|
||||
serverName = server.Host == "" ? server.Hostname : server.Host
|
||||
}
|
||||
},
|
||||
mux = new VMess.OutboundMux
|
||||
mux = new VMessConfig.OutboundMux
|
||||
{
|
||||
enabled = server.UseMux
|
||||
}
|
||||
},
|
||||
mode.Type == 0 || mode.Type == 1 || mode.Type == 2
|
||||
? new VMess.Outbounds
|
||||
? new VMessConfig.Outbounds
|
||||
{
|
||||
tag = "TUNTAP",
|
||||
protocol = "freedom"
|
||||
}
|
||||
: new VMess.Outbounds
|
||||
: new VMessConfig.Outbounds
|
||||
{
|
||||
tag = "direct",
|
||||
protocol = "freedom"
|
||||
}
|
||||
},
|
||||
routing = new VMess.Routing
|
||||
routing = new VMessConfig.Routing
|
||||
{
|
||||
rules = new List<VMess.RoutingRules>
|
||||
rules = new List<VMessConfig.RoutingRules>
|
||||
{
|
||||
mode.BypassChina
|
||||
? new VMess.RoutingRules
|
||||
? new VMessConfig.RoutingRules
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
@@ -155,7 +154,7 @@ namespace Netch.Controllers
|
||||
},
|
||||
outboundTag = "direct"
|
||||
}
|
||||
: new VMess.RoutingRules
|
||||
: new VMessConfig.RoutingRules
|
||||
{
|
||||
type = "field",
|
||||
ip = new List<string>
|
||||
151
Netch/ServerEx/VMess/VMessUtil.cs
Normal file
151
Netch/ServerEx/VMess/VMessUtil.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System.Collections.Generic;
|
||||
using Netch.Models;
|
||||
using Netch.ServerEx.VMess.Form;
|
||||
using Netch.ServerEx.VMess.Models;
|
||||
using Netch.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.ServerEx.VMess
|
||||
{
|
||||
public class VMessUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 2;
|
||||
public string TypeName { get; } = "VMess";
|
||||
public string FullName { get; } = "VMess";
|
||||
public string[] UriScheme { get; } = {"vmess"};
|
||||
|
||||
public Server ParseJObject(JObject j)
|
||||
{
|
||||
return j.ToObject<VMess>();
|
||||
}
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new VMessForm(s).ShowDialog();
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
new VMessForm().ShowDialog();
|
||||
}
|
||||
|
||||
public string GetShareLink(Server s)
|
||||
{
|
||||
var server = (VMess) s;
|
||||
|
||||
var vmessJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
v = "2",
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port,
|
||||
id = server.UserID,
|
||||
aid = server.AlterID,
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecure ? "tls" : ""
|
||||
});
|
||||
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
|
||||
}
|
||||
|
||||
public ServerController GetController()
|
||||
{
|
||||
return new VMessController();
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
var data = new VMess();
|
||||
|
||||
text = text.Substring(8);
|
||||
var vmess = JsonConvert.DeserializeObject<VMessJObject>(ShareLink.URLSafeBase64Decode(text));
|
||||
|
||||
data.Remark = vmess.ps;
|
||||
data.Hostname = vmess.add;
|
||||
data.Port = vmess.port;
|
||||
data.UserID = vmess.id;
|
||||
data.AlterID = vmess.aid;
|
||||
data.TransferProtocol = vmess.net;
|
||||
data.FakeType = vmess.type;
|
||||
|
||||
if (vmess.v == null || vmess.v == "1")
|
||||
{
|
||||
var info = vmess.host.Split(';');
|
||||
if (info.Length == 2)
|
||||
{
|
||||
vmess.host = info[0];
|
||||
vmess.path = info[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (data.TransferProtocol == "quic")
|
||||
{
|
||||
if (VMessGlobal.QUIC.Contains(vmess.host))
|
||||
{
|
||||
data.QUICSecure = vmess.host;
|
||||
data.QUICSecret = vmess.path;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Host = vmess.host;
|
||||
data.Path = vmess.path;
|
||||
}
|
||||
|
||||
data.TLSSecure = vmess.tls == "tls";
|
||||
|
||||
if (vmess.mux == null)
|
||||
{
|
||||
data.UseMux = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vmess.mux.enabled is bool enabled)
|
||||
{
|
||||
data.UseMux = enabled;
|
||||
}
|
||||
else if (vmess.mux.enabled is string muxEnabled)
|
||||
{
|
||||
data.UseMux = muxEnabled == "true"; // 针对使用字符串当作布尔值的情况
|
||||
}
|
||||
else
|
||||
{
|
||||
data.UseMux = false;
|
||||
}
|
||||
}
|
||||
|
||||
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
|
||||
return CheckServer(data) ? new[] {data} : null;
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (VMess) s;
|
||||
if (!VMessGlobal.TransferProtocols.Contains(server.TransferProtocol))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 传输协议:{server.TransferProtocol}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (server.FakeType.Length != 0 && !VMessGlobal.FakeTypes.Contains(server.FakeType))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 伪装类型:{server.FakeType}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (server.TransferProtocol == "quic")
|
||||
{
|
||||
if (!VMessGlobal.QUIC.Contains(server.QUICSecure))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess QUIC 加密方式:{server.QUICSecure}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,14 +49,12 @@ namespace Netch.Utils
|
||||
return mStrSize;
|
||||
}
|
||||
|
||||
public static bool NetTrafficAvailable => /*Global.Settings.EnableNetTraffic && */Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
/// <summary>
|
||||
/// 根据程序名统计流量
|
||||
/// </summary>
|
||||
public static void NetTraffic(Server server, Mode mode)
|
||||
{
|
||||
if (!NetTrafficAvailable)
|
||||
if (!Global.Flags.IsWindows10Upper)
|
||||
return;
|
||||
|
||||
var counterLock = new object();
|
||||
@@ -73,9 +71,9 @@ namespace Netch.Utils
|
||||
{
|
||||
instances.Add(Process.GetCurrentProcess());
|
||||
}
|
||||
else if (MainController.EncryptedProxyController != null)
|
||||
else if (MainController.ServerController != null)
|
||||
{
|
||||
instances.Add(MainController.EncryptedProxyController.Instance);
|
||||
instances.Add(MainController.ServerController.Instance);
|
||||
}
|
||||
else if (MainController.ModeController != null)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using Netch.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -32,45 +26,26 @@ namespace Netch.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
Global.Settings = JsonConvert.DeserializeObject<Setting>(File.ReadAllText(SETTINGS_JSON));
|
||||
if (Global.Settings.Server != null && Global.Settings.Server.Count > 0)
|
||||
var settingJObject = (JObject) JsonConvert.DeserializeObject(File.ReadAllText(SETTINGS_JSON));
|
||||
Global.Settings = settingJObject?.ToObject<Setting>() ?? new Setting();
|
||||
Global.Settings.Server.Clear();
|
||||
|
||||
foreach (JObject server in settingJObject["Server"])
|
||||
{
|
||||
// 如果是旧版 Server 类,使用旧版 Server 类进行读取
|
||||
if (Global.Settings.Server[0].Hostname == null)
|
||||
{
|
||||
var LegacySettingConfig = JsonConvert.DeserializeObject<LegacySetting>(File.ReadAllText(SETTINGS_JSON));
|
||||
for (var i = 0; i < LegacySettingConfig.Server.Count; i++)
|
||||
{
|
||||
Global.Settings.Server[i].Hostname = LegacySettingConfig.Server[i].Address;
|
||||
if (Global.Settings.Server[i].Type == "Shadowsocks")
|
||||
{
|
||||
Global.Settings.Server[i].Type = "SS";
|
||||
Global.Settings.Server[i].Plugin = LegacySettingConfig.Server[i].OBFS;
|
||||
Global.Settings.Server[i].PluginOption = LegacySettingConfig.Server[i].OBFSParam;
|
||||
}
|
||||
else if (Global.Settings.Server[i].Type == "ShadowsocksR")
|
||||
{
|
||||
Global.Settings.Server[i].Type = "SSR";
|
||||
}
|
||||
else if (Global.Settings.Server[i].Type == "VMess")
|
||||
{
|
||||
Global.Settings.Server[i].QUICSecure = LegacySettingConfig.Server[i].QUICSecurity;
|
||||
}
|
||||
}
|
||||
}
|
||||
var serverResult = Servers.ParseJObject(server);
|
||||
if (serverResult != null)
|
||||
Global.Settings.Server.Add(serverResult);
|
||||
}
|
||||
}
|
||||
|
||||
catch (JsonException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 弹出提示
|
||||
i18N.Load("System");
|
||||
// MessageBoxX.Show(i18N.Translate("If this is your first time using this software,\n please check https://netch.org to install supports first,\n or the program may report errors."));
|
||||
|
||||
// 创建 data 文件夹并保存默认设置
|
||||
Save();
|
||||
@@ -86,35 +61,8 @@ namespace Netch.Utils
|
||||
{
|
||||
Directory.CreateDirectory(DATA_DIR);
|
||||
}
|
||||
|
||||
File.WriteAllText(SETTINGS_JSON, JsonConvert.SerializeObject(Global.Settings, Formatting.Indented));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装tap网卡
|
||||
/// </summary>
|
||||
public static void addtap()
|
||||
{
|
||||
Logging.Info("正在安装 TUN/TAP 适配器");
|
||||
//安装Tap Driver
|
||||
var installProcess = new Process();
|
||||
installProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
installProcess.StartInfo.FileName = Path.Combine("bin/tap-driver", "addtap.bat");
|
||||
installProcess.Start();
|
||||
installProcess.WaitForExit();
|
||||
installProcess.Close();
|
||||
}
|
||||
/// <summary>
|
||||
/// 卸载tap网卡
|
||||
/// </summary>
|
||||
public static void deltapall()
|
||||
{
|
||||
Logging.Info("正在卸载 TUN/TAP 适配器");
|
||||
var installProcess = new Process();
|
||||
installProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
installProcess.StartInfo.FileName = Path.Combine("bin/tap-driver", "deltapall.bat");
|
||||
installProcess.Start();
|
||||
installProcess.WaitForExit();
|
||||
installProcess.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -48,51 +46,32 @@ namespace Netch.Utils
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置DNS
|
||||
/// </summary>
|
||||
/// <param name="dns"></param>
|
||||
public static void SetDNS(string[] dns)
|
||||
{
|
||||
ManagementClass wmi = new ManagementClass("Win32_NetworkAdapterConfiguration");
|
||||
ManagementObjectCollection moc = wmi.GetInstances();
|
||||
ManagementBaseObject inPar = null;
|
||||
ManagementBaseObject outPar = null;
|
||||
foreach (ManagementObject mo in moc)
|
||||
{
|
||||
//如果没有启用IP设置的网络设备则跳过,如果是虚拟机网卡也跳过
|
||||
if (!(bool)mo["IPEnabled"] ||
|
||||
mo["Description"].ToString().Contains("Virtual") ||
|
||||
mo["Description"].ToString().Contains("VMware") ||
|
||||
mo["Description"].ToString().Contains("TAP"))
|
||||
continue;
|
||||
|
||||
//设置DNS地址
|
||||
if (dns != null)
|
||||
private static RegistryKey AdapterRegistry(bool write = false)
|
||||
{
|
||||
return Registry.LocalMachine.OpenSubKey(
|
||||
$@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Global.Outbound.Adapter.Id}", write);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出口网卡 DNS
|
||||
/// <para></para>
|
||||
/// 依赖 <see cref="Global.Outbound.Adapter"/>
|
||||
/// </summary>
|
||||
public static string OutboundDNS
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
inPar = mo.GetMethodParameters("SetDNSServerSearchOrder");
|
||||
inPar["DNSServerSearchOrder"] = dns;
|
||||
outPar = mo.InvokeMethod("SetDNSServerSearchOrder", inPar, null);
|
||||
return (string) AdapterRegistry().GetValue("NameServer");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 从网卡获取ip设置信息
|
||||
/// </summary>
|
||||
public static string[] getSystemDns()
|
||||
{
|
||||
var systemDns = new[] { "223.5.5.5", "1.1.1.1" };
|
||||
foreach (var network in NetworkInterface.GetAllNetworkInterfaces())
|
||||
if (!network.Description.Contains("Virtual") &&
|
||||
!network.Description.Contains("VMware") &&
|
||||
!network.Description.Contains("TAP") &&
|
||||
network.OperationalStatus == OperationalStatus.Up &&
|
||||
network.GetIPProperties()?.GatewayAddresses.Count != 0)
|
||||
{
|
||||
systemDns = network.GetIPProperties().DnsAddresses.Select(dns => dns.ToString()).ToArray();
|
||||
}
|
||||
|
||||
return systemDns;
|
||||
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = true)
|
||||
{
|
||||
using var sr = new StringReader(str);
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
if (removeEmptyLines && string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,10 @@ namespace Netch.Utils
|
||||
{
|
||||
"bin/NTT.exe",
|
||||
"bin/Privoxy.exe",
|
||||
"bin/Redirector.exe",
|
||||
"bin/Shadowsocks.exe",
|
||||
"bin/ShadowsocksR.exe",
|
||||
"bin/Trojan.exe",
|
||||
"bin/tun2socks.exe",
|
||||
"bin/unbound.exe",
|
||||
"bin/v2ray.exe",
|
||||
"Netch.exe"
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ using Netch.Models;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
class MessageBoxX
|
||||
static class MessageBoxX
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Netch.Utils
|
||||
Show,
|
||||
Exit
|
||||
}
|
||||
|
||||
|
||||
public static event EventHandler<Commands> Called;
|
||||
|
||||
private static void OnCalled(Commands e)
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using Netch.Controllers;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -107,7 +106,7 @@ namespace Netch.Utils
|
||||
var isUdpUsed = type != PortType.TCP &&
|
||||
(IsPortExcluded(port, PortType.UDP) ||
|
||||
netInfo.GetActiveUdpListeners().Any(ipEndPoint => ipEndPoint.Port == port));
|
||||
var isPortExcluded = !MainController.UsingPorts.Contains(port);
|
||||
var isPortExcluded = !UsingPorts.Contains(port);
|
||||
|
||||
return isPortExcluded && (isTcpUsed || isUdpUsed);
|
||||
}
|
||||
@@ -125,6 +124,11 @@ namespace Netch.Utils
|
||||
|
||||
throw new Exception("Cant Generate Available Port");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录Netch使用的端口
|
||||
/// </summary>
|
||||
public static readonly List<int> UsingPorts = new List<int>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -136,4 +140,8 @@ namespace Netch.Utils
|
||||
UDP,
|
||||
Both
|
||||
}
|
||||
|
||||
public class PortInUseException : Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
51
Netch/Utils/Servers.cs
Normal file
51
Netch/Utils/Servers.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Netch.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Servers
|
||||
{
|
||||
public static readonly IEnumerable<IServerUtil> ServerUtils;
|
||||
|
||||
static Servers()
|
||||
{
|
||||
var serversUtilsTypes = Assembly.GetExecutingAssembly().GetExportedTypes().Where(type => type.GetInterfaces().Any(t => t == typeof(IServerUtil)));
|
||||
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil) Activator.CreateInstance(t)).OrderBy(util => util.Priority);
|
||||
}
|
||||
|
||||
public static Server ParseJObject(JObject o)
|
||||
{
|
||||
var handle = GetUtilByTypeName((string) o["Type"]);
|
||||
if (handle == null)
|
||||
{
|
||||
Logging.Warning($"不支持的服务器类型: {o["Type"]}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return handle.ParseJObject(o);
|
||||
}
|
||||
|
||||
public static IServerUtil GetUtilByTypeName(string typeName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
return null;
|
||||
return ServerUtils.FirstOrDefault(i => (i.TypeName ?? "").Equals(typeName));
|
||||
}
|
||||
|
||||
public static IServerUtil GetUtilByFullName(string fullName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullName))
|
||||
return null;
|
||||
return ServerUtils.FirstOrDefault(i => (i.FullName ?? "").Equals(fullName));
|
||||
}
|
||||
|
||||
public static IServerUtil GetUtilByUriScheme(string typeName)
|
||||
{
|
||||
return ServerUtils.FirstOrDefault(i => i.UriScheme.Any(s => s.Equals(typeName)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Netch.Models;
|
||||
using Netch.Models.SS;
|
||||
using Netch.Models.SSD;
|
||||
using Netch.ServerEx.Shadowsocks;
|
||||
using Netch.ServerEx.Shadowsocks.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Server = Netch.Models.Server;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class ShareLink
|
||||
{
|
||||
#region Utils
|
||||
|
||||
/// <summary>
|
||||
/// URL 传输安全的 Base64 解码
|
||||
/// </summary>
|
||||
/// <param name="text">需要解码的字符串</param>
|
||||
/// <returns>解码后的字符串</returns>
|
||||
/// URL 传输安全的 Base64 解码
|
||||
/// </summary>
|
||||
/// <param name="text">需要解码的字符串</param>
|
||||
/// <returns>解码后的字符串</returns>
|
||||
public static string URLSafeBase64Decode(string text)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(text.Replace("-", "+").Replace("_", "/").PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL 传输安全的 Base64 加密
|
||||
/// </summary>
|
||||
@@ -33,82 +35,111 @@ namespace Netch.Utils
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).Replace("+", "-").Replace("/", "_").Replace("=", "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据服务器生成分享链接
|
||||
/// </summary>
|
||||
/// <param name="server">需要获取分享链接的服务器</param>
|
||||
/// <returns>解码后的字符串</returns>
|
||||
public static string GetShareLink(Server server)
|
||||
private static string RemoveEmoji(string text)
|
||||
{
|
||||
var retLinkStr = "";
|
||||
switch (server.Type)
|
||||
{
|
||||
case "Socks5":
|
||||
// https://t.me/socks?server=1.1.1.1&port=443
|
||||
retLinkStr = string.Format("https://t.me/socks?server={0}&port={1}", server.Hostname, server.Port);
|
||||
|
||||
break;
|
||||
case "SS":
|
||||
// ss://method:password@server:port#Remark
|
||||
retLinkStr = "ss://" + URLSafeBase64Encode(string.Format("{0}:{1}@{2}:{3}", server.EncryptMethod, server.Password, server.Hostname, server.Port)) + "#" + HttpUtility.UrlEncode(server.Remark);
|
||||
|
||||
break;
|
||||
case "SSR":
|
||||
// https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
|
||||
// ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
||||
var paraStr = string.Format("/?obfsparam={0}&protoparam={1}&remarks={2}", URLSafeBase64Encode(server.OBFSParam), URLSafeBase64Encode(server.ProtocolParam), URLSafeBase64Encode(server.Remark));
|
||||
retLinkStr = "ssr://" + URLSafeBase64Encode(string.Format("{0}:{1}:{2}:{3}:{4}:{5}{6}", server.Hostname, server.Port, server.Protocol, server.EncryptMethod, server.OBFS, URLSafeBase64Encode(server.Password), paraStr));
|
||||
|
||||
break;
|
||||
case "VMess":
|
||||
var vmessJson = JsonConvert.SerializeObject(new
|
||||
{
|
||||
v = "2",
|
||||
ps = server.Remark,
|
||||
add = server.Hostname,
|
||||
port = server.Port,
|
||||
id = server.UserID,
|
||||
aid = server.AlterID,
|
||||
net = server.TransferProtocol,
|
||||
type = server.FakeType,
|
||||
host = server.Host,
|
||||
path = server.Path,
|
||||
tls = server.TLSSecure ? "tls" : ""
|
||||
});
|
||||
retLinkStr = "vmess://" + URLSafeBase64Encode(vmessJson);
|
||||
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return retLinkStr;
|
||||
byte[] emojiBytes = {240, 159};
|
||||
var remark = Encoding.UTF8.GetBytes(text);
|
||||
var startIndex = 0;
|
||||
while (remark.Length > startIndex + 1 && remark[startIndex] == emojiBytes[0] && remark[startIndex + 1] == emojiBytes[1])
|
||||
startIndex += 4;
|
||||
return Encoding.UTF8.GetString(remark.Skip(startIndex).ToArray()).Trim();
|
||||
}
|
||||
|
||||
public static List<Server> Parse(string text)
|
||||
|
||||
public static string UnBase64String(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var bytes = Convert.FromBase64String(value);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
public static string ToBase64String(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> ParseParam(string paramStr)
|
||||
{
|
||||
var paramsDict = new Dictionary<string, string>();
|
||||
var obfsParams = paramStr.Split('&');
|
||||
foreach (var p in obfsParams)
|
||||
{
|
||||
if (p.IndexOf('=') > 0)
|
||||
{
|
||||
var index = p.IndexOf('=');
|
||||
var key = p.Substring(0, index);
|
||||
var val = p.Substring(index + 1);
|
||||
paramsDict[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return paramsDict;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = true)
|
||||
{
|
||||
using var sr = new StringReader(str);
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
if (removeEmptyLines && string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static string GetShareLink(Server server)
|
||||
{
|
||||
return Servers.GetUtilByTypeName(server.Type).GetShareLink(server);
|
||||
}
|
||||
|
||||
public static List<Server> ParseText(string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
text = URLSafeBase64Decode(text);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
var list = new List<Server>();
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var ssServers = JsonConvert.DeserializeObject<List<ShadowsocksServer>>(text);
|
||||
list.AddRange(ssServers.Select(shadowsocksServer => new Server
|
||||
list.AddRange(JsonConvert.DeserializeObject<List<ShadowsocksConfig>>(text).Select(server => new Shadowsocks
|
||||
{
|
||||
Type = "SS",
|
||||
Hostname = shadowsocksServer.server,
|
||||
Port = shadowsocksServer.server_port,
|
||||
EncryptMethod = shadowsocksServer.method,
|
||||
Password = shadowsocksServer.password,
|
||||
Remark = shadowsocksServer.remarks,
|
||||
Plugin = shadowsocksServer.plugin,
|
||||
PluginOption = shadowsocksServer.plugin_opts
|
||||
Hostname = server.server,
|
||||
Port = server.server_port,
|
||||
EncryptMethod = server.method,
|
||||
Password = server.password,
|
||||
Remark = server.remarks,
|
||||
Plugin = server.plugin,
|
||||
PluginOption = server.plugin_opts
|
||||
}));
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
foreach (var line in text.GetLines())
|
||||
{
|
||||
var servers = ParseLine(line);
|
||||
var servers = ParseUri(line);
|
||||
if (servers != null)
|
||||
{
|
||||
list.AddRange(servers);
|
||||
@@ -130,7 +161,7 @@ namespace Netch.Utils
|
||||
return list;
|
||||
}
|
||||
|
||||
private static IEnumerable<Server> ParseLine(string text)
|
||||
private static IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
var list = new List<Server>();
|
||||
|
||||
@@ -138,356 +169,23 @@ namespace Netch.Utils
|
||||
{
|
||||
if (text.StartsWith("tg://socks?") || text.StartsWith("https://t.me/socks?"))
|
||||
{
|
||||
var data = new Server();
|
||||
data.Type = "Socks5";
|
||||
|
||||
var dict = new Dictionary<string, string>();
|
||||
foreach (var str in text.Replace("tg://socks?", "").Replace("https://t.me/socks?", "").Split('&'))
|
||||
{
|
||||
var splited = str.Split('=');
|
||||
|
||||
dict.Add(splited[0], splited[1]);
|
||||
}
|
||||
|
||||
if (!dict.ContainsKey("server") || !dict.ContainsKey("port"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
data.Hostname = dict["server"];
|
||||
data.Port = int.Parse(dict["port"]);
|
||||
if (dict.ContainsKey("user") && !string.IsNullOrWhiteSpace(dict["user"]))
|
||||
{
|
||||
data.Username = dict["user"];
|
||||
}
|
||||
if (dict.ContainsKey("pass") && !string.IsNullOrWhiteSpace(dict["pass"]))
|
||||
{
|
||||
data.Password = dict["pass"];
|
||||
}
|
||||
|
||||
list.Add(data);
|
||||
}
|
||||
else if (text.StartsWith("ss://"))
|
||||
{
|
||||
var data = new Server();
|
||||
data.Type = "SS";
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
try
|
||||
{
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var finder = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var match = finder.Match(text);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var plugins = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("plugin"));
|
||||
if (plugins != null)
|
||||
{
|
||||
var plugin = plugins.Substring(0, plugins.IndexOf(";", StringComparison.Ordinal));
|
||||
var pluginopts = plugins.Substring(plugins.IndexOf(";", StringComparison.Ordinal) + 1);
|
||||
if (plugin == "obfs-local" || plugin == "simple-obfs")
|
||||
{
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=http;obfs-host=" + pluginopts;
|
||||
}
|
||||
else if (plugin == "simple-obfs-tls")
|
||||
{
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=tls;obfs-host=" + pluginopts;
|
||||
}
|
||||
|
||||
data.Plugin = plugin;
|
||||
data.PluginOption = pluginopts;
|
||||
}
|
||||
|
||||
text = match.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
if (text.Contains("@"))
|
||||
{
|
||||
var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
|
||||
var base64 = URLSafeBase64Decode(match.Groups["base64"].Value);
|
||||
match = parser.Match(base64);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parser = new Regex(@"^((?<method>.+?):(?<password>.+)@(?<server>.+):(?<port>\d+))");
|
||||
var match = parser.Match(URLSafeBase64Decode(text.Replace("ss://", "")));
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
}
|
||||
|
||||
if (!Global.EncryptMethods.SS.Contains(data.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SS 加密方式:{data.EncryptMethod}");
|
||||
return null;
|
||||
}
|
||||
|
||||
list.Add(data);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (text.StartsWith("ssd://"))
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<Main>(URLSafeBase64Decode(text.Substring(6)));
|
||||
|
||||
foreach (var server in json.servers)
|
||||
{
|
||||
var data = new Server();
|
||||
data.Type = "SS";
|
||||
|
||||
data.Remark = server.remarks;
|
||||
data.Hostname = server.server;
|
||||
data.Port = server.port != 0 ? server.port : json.port;
|
||||
data.Password = server.password != null ? server.password : json.password;
|
||||
data.EncryptMethod = server.encryption != null ? server.encryption : json.encryption;
|
||||
data.Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin;
|
||||
data.PluginOption = string.IsNullOrEmpty(json.plugin_options) ? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options : json.plugin_options;
|
||||
|
||||
if (Global.EncryptMethods.SS.Contains(data.EncryptMethod))
|
||||
{
|
||||
list.Add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (text.StartsWith("ssr://"))
|
||||
{
|
||||
|
||||
list.Add(SsrServerFromLink(text));
|
||||
|
||||
}
|
||||
else if (text.StartsWith("vmess://"))
|
||||
{
|
||||
var data = new Server();
|
||||
data.Type = "VMess";
|
||||
|
||||
text = text.Substring(8);
|
||||
var vmess = JsonConvert.DeserializeObject<VMess>(URLSafeBase64Decode(text));
|
||||
|
||||
data.Remark = vmess.ps;
|
||||
data.Hostname = vmess.add;
|
||||
data.Port = vmess.port;
|
||||
data.UserID = vmess.id;
|
||||
data.AlterID = vmess.aid;
|
||||
|
||||
data.TransferProtocol = vmess.net;
|
||||
if (!Global.TransferProtocols.Contains(data.TransferProtocol))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 传输协议:{data.TransferProtocol}");
|
||||
return null;
|
||||
}
|
||||
|
||||
data.FakeType = vmess.type;
|
||||
if (data.FakeType.Length != 0 && !Global.FakeTypes.Contains(data.FakeType))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 伪装类型:{data.FakeType}");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (vmess.v == null || vmess.v == "1")
|
||||
{
|
||||
var info = vmess.host.Split(';');
|
||||
if (info.Length == 2)
|
||||
{
|
||||
vmess.host = info[0];
|
||||
vmess.path = info[1];
|
||||
}
|
||||
}
|
||||
if (data.TransferProtocol == "quic")
|
||||
{
|
||||
if (!Global.EncryptMethods.VMessQUIC.Contains(vmess.host))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess QUIC 加密方式:{vmess.host}");
|
||||
return null;
|
||||
}
|
||||
|
||||
data.QUICSecure = vmess.host;
|
||||
data.QUICSecret = vmess.path;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Host = vmess.host;
|
||||
data.Path = vmess.path;
|
||||
}
|
||||
data.TLSSecure = vmess.tls == "tls";
|
||||
|
||||
if (vmess.mux == null)
|
||||
{
|
||||
data.UseMux = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vmess.mux.enabled is bool enabled)
|
||||
{
|
||||
data.UseMux = enabled;
|
||||
}
|
||||
else if (vmess.mux.enabled is string muxEnabled)
|
||||
{
|
||||
data.UseMux = muxEnabled == "true"; // 针对使用字符串当作布尔值的情况
|
||||
}
|
||||
else
|
||||
{
|
||||
data.UseMux = false;
|
||||
}
|
||||
}
|
||||
|
||||
data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个
|
||||
|
||||
list.Add(data);
|
||||
list.AddRange(Servers.GetUtilByTypeName("Socks5").ParseUri(text));
|
||||
}
|
||||
else if (text.StartsWith("Netch://"))
|
||||
{
|
||||
text = text.Substring(8);
|
||||
var NetchLink = JsonConvert.DeserializeObject<Server>(URLSafeBase64Decode(text));
|
||||
if (!string.IsNullOrEmpty(NetchLink.Hostname) || NetchLink.Port > 65536 || NetchLink.Port > 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (NetchLink.Type)
|
||||
{
|
||||
case "Socks5":
|
||||
list.Add(NetchLink);
|
||||
break;
|
||||
case "SS":
|
||||
if (!Global.EncryptMethods.SS.Contains(NetchLink.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SS 加密方式:{NetchLink.EncryptMethod}");
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "SSR":
|
||||
if (!Global.EncryptMethods.SSR.Contains(NetchLink.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 加密方式:{NetchLink.EncryptMethod}");
|
||||
return null;
|
||||
}
|
||||
if (!Global.Protocols.Contains(NetchLink.Protocol))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 协议:{NetchLink.Protocol}");
|
||||
return null;
|
||||
}
|
||||
if (!Global.OBFSs.Contains(NetchLink.OBFS))
|
||||
{
|
||||
Logging.Error($"不支持的 SSR 混淆:{NetchLink.OBFS}");
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "VMess":
|
||||
if (!Global.TransferProtocols.Contains(NetchLink.TransferProtocol))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 传输协议:{NetchLink.TransferProtocol}");
|
||||
return null;
|
||||
}
|
||||
if (!Global.FakeTypes.Contains(NetchLink.FakeType))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess 伪装类型:{NetchLink.FakeType}");
|
||||
return null;
|
||||
}
|
||||
if (NetchLink.TransferProtocol == "quic")
|
||||
{
|
||||
if (!Global.EncryptMethods.VMessQUIC.Contains(NetchLink.QUICSecure))
|
||||
{
|
||||
Logging.Error($"不支持的 VMess QUIC 加密方式:{NetchLink.QUICSecure}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
list.Add(NetchLink);
|
||||
list.Add(ParseNetchUri(text));
|
||||
}
|
||||
else if (text.StartsWith("trojan://"))
|
||||
else
|
||||
{
|
||||
var data = new Server();
|
||||
data.Type = "Trojan";
|
||||
|
||||
text = text.Replace("/?", "?");
|
||||
try
|
||||
{
|
||||
if (text.Contains("#"))
|
||||
{
|
||||
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
|
||||
text = text.Split('#')[0];
|
||||
}
|
||||
if (text.Contains("?"))
|
||||
{
|
||||
var reg = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
var regmatch = reg.Match(text);
|
||||
|
||||
if (regmatch.Success)
|
||||
{
|
||||
var peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("peer"));
|
||||
|
||||
if (peer != null)
|
||||
data.Host = peer;
|
||||
|
||||
text = regmatch.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
var finder = new Regex(@"^trojan://(?<psk>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
data.Password = match.Groups["psk"].Value;
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = int.Parse(match.Groups["port"].Value);
|
||||
|
||||
list.Add(data);
|
||||
}
|
||||
catch (FormatException)
|
||||
var scheme = GetUriScheme(text);
|
||||
var util = Servers.GetUtilByUriScheme(scheme);
|
||||
if (util == null)
|
||||
{
|
||||
Logging.Warning($"无法处理 {scheme} 协议订阅链接");
|
||||
return null;
|
||||
}
|
||||
|
||||
list.AddRange(util.ParseUri(text));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -496,135 +194,49 @@ namespace Netch.Utils
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] emoji_bytes = { 240, 159 };
|
||||
foreach (var node in list)
|
||||
{
|
||||
var remark = Encoding.UTF8.GetBytes(node.Remark);
|
||||
var start_index = 0;
|
||||
while (remark.Length > start_index + 1 && remark[start_index] == emoji_bytes[0] && remark[start_index + 1] == emoji_bytes[1])
|
||||
start_index += 4;
|
||||
node.Remark = Encoding.UTF8.GetString(remark.Skip(start_index).ToArray()).Trim();
|
||||
node.Remark = RemoveEmoji(node.Remark);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
public static string UnBase64String(string value)
|
||||
{
|
||||
if (value == null || value == "")
|
||||
{
|
||||
return "";
|
||||
}
|
||||
var bytes = Convert.FromBase64String(value);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
public static string ToBase64String(string value)
|
||||
{
|
||||
if (value == null || value == "")
|
||||
{
|
||||
return "";
|
||||
}
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
return Convert.ToBase64String(bytes);
|
||||
return list.Where(s => s != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SSR链接解析器
|
||||
/// Copy From https://github.com/HMBSbige/ShadowsocksR-Windows/blob/d9dc8d032a6e04c14b9dc6c8f673c9cc5aa9f607/shadowsocks-csharp/Model/Server.cs#L428
|
||||
/// Thx :D
|
||||
/// </summary>
|
||||
/// <param name="ssrUrl"></param>
|
||||
/// <returns></returns>
|
||||
public static Server SsrServerFromLink(string ssrUrl)
|
||||
private static string GetUriScheme(string text)
|
||||
{
|
||||
// ssr://host:port:protocol:method:obfs:base64pass/?obfsparam=base64&remarks=base64&group=base64&udpport=0&uot=1
|
||||
var ssr = Regex.Match(ssrUrl, "ssr://([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase);
|
||||
if (!ssr.Success)
|
||||
throw new FormatException();
|
||||
|
||||
var data = URLSafeBase64Decode(ssr.Groups[1].Value);
|
||||
var params_dict = new Dictionary<string, string>();
|
||||
|
||||
var param_start_pos = data.IndexOf("?", StringComparison.Ordinal);
|
||||
if (param_start_pos > 0)
|
||||
{
|
||||
params_dict = ParseParam(data.Substring(param_start_pos + 1));
|
||||
data = data.Substring(0, param_start_pos);
|
||||
}
|
||||
if (data.IndexOf("/", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
var UrlFinder = new Regex("^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)");
|
||||
var match = UrlFinder.Match(data);
|
||||
|
||||
if (match == null || !match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
var serverAddr = match.Groups[1].Value;
|
||||
var Server_Port = ushort.Parse(match.Groups[2].Value);
|
||||
var Protocol = match.Groups[3].Value.Length == 0 ? "origin" : match.Groups[3].Value;
|
||||
Protocol = Protocol.Replace("_compatible", "");
|
||||
var Method = match.Groups[4].Value;
|
||||
var obfs = match.Groups[5].Value.Length == 0 ? "plain" : match.Groups[5].Value;
|
||||
obfs = obfs.Replace("_compatible", "");
|
||||
var Password = URLSafeBase64Decode(match.Groups[6].Value);
|
||||
var ProtocolParam = "";
|
||||
var ObfsParam = "";
|
||||
var Remarks = "";
|
||||
var Group = "";
|
||||
|
||||
if (params_dict.ContainsKey("protoparam"))
|
||||
{
|
||||
ProtocolParam = URLSafeBase64Decode(params_dict["protoparam"]);
|
||||
}
|
||||
if (params_dict.ContainsKey("obfsparam"))
|
||||
{
|
||||
ObfsParam = URLSafeBase64Decode(params_dict["obfsparam"]);
|
||||
}
|
||||
if (params_dict.ContainsKey("remarks"))
|
||||
{
|
||||
Remarks = URLSafeBase64Decode(params_dict["remarks"]);
|
||||
}
|
||||
Group = params_dict.ContainsKey("group") ? URLSafeBase64Decode(params_dict["group"]) : string.Empty;
|
||||
|
||||
/*if (params_dict.ContainsKey("uot"))
|
||||
{
|
||||
UdpOverTcp = int.Parse(params_dict["uot"]) != 0;
|
||||
}
|
||||
if (params_dict.ContainsKey("udpport"))
|
||||
{
|
||||
Server_Udp_Port = ushort.Parse(params_dict["udpport"]);
|
||||
}*/
|
||||
var server = new Server();
|
||||
server.Type = "SSR";
|
||||
server.Hostname = serverAddr;
|
||||
server.Port = Server_Port;
|
||||
server.Protocol = Protocol;
|
||||
server.EncryptMethod = Method;
|
||||
server.OBFS = obfs;
|
||||
server.Password = Password;
|
||||
server.ProtocolParam = ProtocolParam;
|
||||
server.OBFSParam = ObfsParam;
|
||||
server.Remark = Remarks;
|
||||
server.Group = Group;
|
||||
return server;
|
||||
var endIndex = text.IndexOf("://", StringComparison.Ordinal);
|
||||
if (endIndex == -1)
|
||||
throw new UriFormatException("Text is not a URI");
|
||||
return text.Substring(0, endIndex);
|
||||
}
|
||||
private static Dictionary<string, string> ParseParam(string paramStr)
|
||||
|
||||
private static Server ParseNetchUri(string text)
|
||||
{
|
||||
var paramsDict = new Dictionary<string, string>();
|
||||
var obfsParams = paramStr.Split('&');
|
||||
foreach (var p in obfsParams)
|
||||
text = text.Substring(8);
|
||||
var NetchLink = (JObject) JsonConvert.DeserializeObject(URLSafeBase64Decode(text));
|
||||
if (NetchLink == null)
|
||||
{
|
||||
if (p.IndexOf('=') > 0)
|
||||
{
|
||||
var index = p.IndexOf('=');
|
||||
var key = p.Substring(0, index);
|
||||
var val = p.Substring(index + 1);
|
||||
paramsDict[key] = val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return paramsDict;
|
||||
|
||||
if (string.IsNullOrEmpty((string) NetchLink["Hostname"]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ushort.TryParse((string) NetchLink["Port"], out _))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var type = (string) NetchLink["Type"];
|
||||
var s = Servers.GetUtilByTypeName(type).ParseJObject(NetchLink);
|
||||
return Servers.GetUtilByTypeName(s.Type).CheckServer(s) ? s : null;
|
||||
}
|
||||
|
||||
public static string GetNetchLink(Server s)
|
||||
{
|
||||
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Netch.Utils
|
||||
@@ -62,5 +64,30 @@ namespace Netch.Utils
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载tap网卡
|
||||
/// </summary>
|
||||
public static void deltapall()
|
||||
{
|
||||
Logging.Info("正在卸载 TUN/TAP 适配器");
|
||||
var installProcess = new Process {StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "deltapall.bat")}};
|
||||
installProcess.Start();
|
||||
installProcess.WaitForExit();
|
||||
installProcess.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装tap网卡
|
||||
/// </summary>
|
||||
public static void addtap()
|
||||
{
|
||||
Logging.Info("正在安装 TUN/TAP 适配器");
|
||||
//安装Tap Driver
|
||||
var installProcess = new Process {StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "addtap.bat")}};
|
||||
installProcess.Start();
|
||||
installProcess.WaitForExit();
|
||||
installProcess.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
using MaxMind.GeoIP2;
|
||||
using System;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using MaxMind.GeoIP2;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
@@ -19,7 +20,7 @@ namespace Netch.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo()
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "explorer.exe",
|
||||
Arguments = path,
|
||||
@@ -65,7 +66,7 @@ namespace Netch.Utils
|
||||
{
|
||||
var databaseReader = new DatabaseReader("bin\\GeoLite2-Country.mmdb");
|
||||
|
||||
if (IPAddress.TryParse(Hostname, out _) == true)
|
||||
if (IPAddress.TryParse(Hostname, out _))
|
||||
{
|
||||
Country = databaseReader.Country(Hostname).Country.IsoCode;
|
||||
}
|
||||
@@ -95,7 +96,7 @@ namespace Netch.Utils
|
||||
{
|
||||
try
|
||||
{
|
||||
var SHA256 = SHA256Managed.Create();
|
||||
var SHA256 = System.Security.Cryptography.SHA256.Create();
|
||||
var fileStream = File.OpenRead(filePath);
|
||||
return SHA256.ComputeHash(fileStream).Aggregate(string.Empty, (current, b) => current + b.ToString("x2"));
|
||||
}
|
||||
@@ -105,18 +106,145 @@ namespace Netch.Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsZipValid(string path)
|
||||
public static void KillProcessByName(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var zipFile = ZipFile.OpenRead(path);
|
||||
_ = zipFile.Entries;
|
||||
return true;
|
||||
foreach (var p in Process.GetProcessesByName(name))
|
||||
if (p.MainModule != null && p.MainModule.FileName.StartsWith(Global.NetchDir))
|
||||
p.Kill();
|
||||
}
|
||||
catch (InvalidDataException)
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Logging.Error($"结束进程 {name} 错误:" + e.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static string FileVersion(string file) => File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty;
|
||||
|
||||
public static bool SearchOutboundAdapter(bool log = true)
|
||||
{
|
||||
IPAddress localEnd;
|
||||
try
|
||||
{
|
||||
localEnd = WebUtil.BestLocalEndPoint(new IPEndPoint(0x72727272, 53)).Address;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 根据 IP 寻找 出口适配器
|
||||
Global.Outbound.Adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _.GetIPProperties().UnicastAddresses.Any(ip =>
|
||||
{
|
||||
if (ip.Address.AddressFamily == AddressFamily.InterNetwork && ip.Address.ToString().Equals(localEnd.ToString()))
|
||||
{
|
||||
Global.Outbound.Index = _.GetIPProperties().GetIPv4Properties().Index;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Global.Outbound.Gateway = Global.Outbound.Adapter.GetIPProperties().GatewayAddresses[0].Address;
|
||||
if (log)
|
||||
{
|
||||
Logging.Info($"出口 IPv4 地址:{Global.Outbound.Address}");
|
||||
Logging.Info($"出口 网关 地址:{Global.Outbound.Gateway}");
|
||||
Logging.Info($"出口适配器:{Global.Outbound.Adapter.Name} {Global.Outbound.Adapter.Id} {Global.Outbound.Adapter.Description}, index: {Global.Outbound.Index}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error($"找不到出口IP所在网卡: {e}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoggingAdapters(string id)
|
||||
{
|
||||
var adapter = NetworkInterface.GetAllNetworkInterfaces().First(adapter => adapter.Id == id);
|
||||
Logging.Warning($"检索此网卡信息出错: {adapter.Name} {adapter.Id} {adapter.Description}");
|
||||
}
|
||||
|
||||
public static void DrawCenterComboBox(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox cbx)
|
||||
{
|
||||
e.DrawBackground();
|
||||
|
||||
if (e.Index >= 0)
|
||||
{
|
||||
var brush = new SolidBrush(cbx.ForeColor);
|
||||
|
||||
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
||||
brush = SystemBrushes.HighlightText as SolidBrush;
|
||||
|
||||
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment = StringAlignment.Center
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ComponentIterator(Component component, Action<Component> func)
|
||||
{
|
||||
func.Invoke(component);
|
||||
switch (component)
|
||||
{
|
||||
case ToolStripMenuItem toolStripMenuItem:
|
||||
// Iterator Menu strip sub item
|
||||
foreach (var item in toolStripMenuItem.DropDownItems.Cast<ToolStripItem>())
|
||||
{
|
||||
ComponentIterator(item, func);
|
||||
}
|
||||
|
||||
break;
|
||||
case MenuStrip menuStrip:
|
||||
// Menu Strip
|
||||
foreach (var item in menuStrip.Items.Cast<ToolStripItem>())
|
||||
{
|
||||
ComponentIterator(item, func);
|
||||
}
|
||||
|
||||
break;
|
||||
case ContextMenuStrip contextMenuStrip:
|
||||
foreach (var item in contextMenuStrip.Items.Cast<ToolStripItem>())
|
||||
{
|
||||
ComponentIterator(item, func);
|
||||
}
|
||||
|
||||
break;
|
||||
case Control control:
|
||||
foreach (var c in control.Controls.Cast<Control>())
|
||||
{
|
||||
ComponentIterator(c, func);
|
||||
}
|
||||
|
||||
if (control.ContextMenuStrip != null)
|
||||
ComponentIterator(control.ContextMenuStrip, func);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -26,6 +25,12 @@ namespace Netch.Utils
|
||||
return req;
|
||||
}
|
||||
|
||||
public static IPEndPoint BestLocalEndPoint(IPEndPoint remoteIPEndPoint)
|
||||
{
|
||||
var testSocket = new Socket(remoteIPEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
testSocket.Connect(remoteIPEndPoint);
|
||||
return (IPEndPoint) testSocket.LocalEndPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Netch.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -104,5 +105,24 @@ namespace Netch.Utils
|
||||
translateFile.AddRange(Directory.GetFiles("i18n", "*").Select(fileName => fileName.Substring(5)));
|
||||
return translateFile;
|
||||
}
|
||||
|
||||
public static void TranslateForm(Control c)
|
||||
{
|
||||
Utils.ComponentIterator(c, component =>
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
break;
|
||||
case Control c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
case ToolStripItem c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,347 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public static class Win32Native
|
||||
{
|
||||
public enum ForwardType
|
||||
{
|
||||
Other = 1,
|
||||
Invalid = 2,
|
||||
Direct = 3,
|
||||
Indirect = 4
|
||||
}
|
||||
|
||||
public enum ForwardProtocol
|
||||
{
|
||||
Other = 1,
|
||||
Local = 2,
|
||||
NetMGMT = 3,
|
||||
ICMP = 4,
|
||||
EGP = 5,
|
||||
GGP = 6,
|
||||
Hello = 7,
|
||||
RIP = 8,
|
||||
IS_IS = 9,
|
||||
ES_IS = 10, // 0x0000000A
|
||||
CISCO = 11, // 0x0000000B
|
||||
BBN = 12, // 0x0000000C
|
||||
OSPF = 13, // 0x0000000D
|
||||
BGP = 14, // 0x0000000E
|
||||
NT_AUTOSTATIC = 10002, // 0x00002712
|
||||
NT_STATIC = 10006, // 0x00002716
|
||||
NT_STATIC_NON_DOD = 10007 // 0x00002717
|
||||
}
|
||||
|
||||
public class RouteEntry
|
||||
{
|
||||
internal MIB_IPFORWARDROW _ipFwdNative;
|
||||
private int _metric1;
|
||||
private int _metric2;
|
||||
private int _metric3;
|
||||
private int _metric4;
|
||||
private int _metric5;
|
||||
private IPAddress _destination;
|
||||
private IPAddress _mask;
|
||||
private int _policy;
|
||||
private IPAddress _nextHop;
|
||||
private NetworkInterface _interface;
|
||||
private ForwardProtocol _protocol;
|
||||
private ForwardType _type;
|
||||
private int _nextHopAS;
|
||||
private int _age;
|
||||
private int _index;
|
||||
|
||||
public int Index
|
||||
{
|
||||
get => _index;
|
||||
set => _index = value;
|
||||
}
|
||||
|
||||
public IPAddress Destination
|
||||
{
|
||||
get => _destination;
|
||||
set => _destination = value;
|
||||
}
|
||||
|
||||
public IPAddress Mask
|
||||
{
|
||||
get => _mask;
|
||||
set => _mask = value;
|
||||
}
|
||||
|
||||
public int Policy
|
||||
{
|
||||
get => _policy;
|
||||
set => _policy = value;
|
||||
}
|
||||
|
||||
public IPAddress NextHop
|
||||
{
|
||||
get => _nextHop;
|
||||
set => _nextHop = value;
|
||||
}
|
||||
|
||||
public NetworkInterface RelatedInterface => _interface;
|
||||
|
||||
public string InterfaceName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RelatedInterface == null)
|
||||
return string.Empty;
|
||||
return RelatedInterface.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public ForwardType ForwardType
|
||||
{
|
||||
get => _type;
|
||||
set => _type = value;
|
||||
}
|
||||
|
||||
public ForwardProtocol Protocol
|
||||
{
|
||||
get => _protocol;
|
||||
set => _protocol = value;
|
||||
}
|
||||
|
||||
public int Age
|
||||
{
|
||||
get => _age;
|
||||
set => _age = value;
|
||||
}
|
||||
|
||||
public int NextHopAS
|
||||
{
|
||||
get => _nextHopAS;
|
||||
set => _nextHopAS = value;
|
||||
}
|
||||
|
||||
public int Metric1
|
||||
{
|
||||
get => _metric1;
|
||||
set => _metric1 = value;
|
||||
}
|
||||
|
||||
public int Metric2
|
||||
{
|
||||
get => _metric2;
|
||||
set => _metric2 = value;
|
||||
}
|
||||
|
||||
public int Metric3
|
||||
{
|
||||
get => _metric3;
|
||||
set => _metric3 = value;
|
||||
}
|
||||
|
||||
public int Metric4
|
||||
{
|
||||
get => _metric4;
|
||||
set => _metric4 = value;
|
||||
}
|
||||
|
||||
public int Metric5
|
||||
{
|
||||
get => _metric5;
|
||||
set => _metric5 = value;
|
||||
}
|
||||
|
||||
public RouteEntry(
|
||||
uint destination,
|
||||
uint mask,
|
||||
int policy,
|
||||
uint nextHop,
|
||||
NetworkInterface intf,
|
||||
ForwardType type,
|
||||
ForwardProtocol proto,
|
||||
int age,
|
||||
int nextHopAS,
|
||||
int metric1,
|
||||
int metric2,
|
||||
int metric3,
|
||||
int metric4,
|
||||
int metric5,
|
||||
int idx)
|
||||
{
|
||||
_age = age;
|
||||
_policy = policy;
|
||||
_protocol = proto;
|
||||
_type = type;
|
||||
_destination = new IPAddress(destination);
|
||||
_mask = new IPAddress(mask);
|
||||
_nextHop = new IPAddress(nextHop);
|
||||
_nextHopAS = nextHopAS;
|
||||
_interface = intf;
|
||||
_metric1 = metric1;
|
||||
_metric2 = metric2;
|
||||
_metric3 = metric3;
|
||||
_metric4 = metric4;
|
||||
_metric5 = metric5;
|
||||
_index = idx;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct MIB_IFROW
|
||||
{
|
||||
private const int MAX_INTERFACE_NAME_LEN = 256;
|
||||
private const int MAXLEN_IFDESCR = 256;
|
||||
private const int MAXLEN_PHYSADDR = 8;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string wszName;
|
||||
public int dwIndex;
|
||||
public int dwType;
|
||||
public int dwMtu;
|
||||
public int dwSpeed;
|
||||
public int dwPhysAddrLen;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] bPhysAddr;
|
||||
public int dwAdminStatus;
|
||||
public int dwOperStatus;
|
||||
public int dwLastChange;
|
||||
public int dwInOctets;
|
||||
public int dwInUcastPkts;
|
||||
public int dwInNUcastPkts;
|
||||
public int dwInDiscards;
|
||||
public int dwInErrors;
|
||||
public int dwInUnknownProtos;
|
||||
public int dwOutOctets;
|
||||
public int dwOutUcastPkts;
|
||||
public int dwOutNUcastPkts;
|
||||
public int dwOutDiscards;
|
||||
public int dwOutErrors;
|
||||
public int dwOutQLen;
|
||||
public int dwDescrLen;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public byte[] bDescr;
|
||||
}
|
||||
|
||||
public class AdaptersTable
|
||||
{
|
||||
private Dictionary<int, NetworkInterface> _adapters = new Dictionary<int, NetworkInterface>();
|
||||
|
||||
public IDictionary<int, NetworkInterface> GetAdapters()
|
||||
{
|
||||
return _adapters;
|
||||
}
|
||||
|
||||
public NetworkInterface GetAdapter(int interfaceIndex)
|
||||
{
|
||||
NetworkInterface networkInterface = null;
|
||||
_adapters.TryGetValue(interfaceIndex, out networkInterface);
|
||||
return networkInterface;
|
||||
}
|
||||
|
||||
public int GetAdapterIndex(NetworkInterface networkInterface)
|
||||
{
|
||||
return _adapters.First(a => a.Value == networkInterface).Key;
|
||||
}
|
||||
|
||||
public AdaptersTable()
|
||||
{
|
||||
var num1 = IntPtr.Zero;
|
||||
var pdwSize = 0;
|
||||
var num2 = 0;
|
||||
num2 = GetIfTable(IntPtr.Zero, ref pdwSize, true);
|
||||
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
try
|
||||
{
|
||||
num1 = Marshal.AllocHGlobal(pdwSize);
|
||||
if (GetIfTable(num1, ref pdwSize, true) != 0)
|
||||
return;
|
||||
var num3 = Marshal.ReadInt32(num1);
|
||||
var ptr = new IntPtr(num1.ToInt32() + 4);
|
||||
for (var index = 0; index < num3; ++index)
|
||||
{
|
||||
var structure = (MIB_IFROW)Marshal.PtrToStructure(ptr, typeof(MIB_IFROW));
|
||||
var pIfRow = new MIB_IFROW();
|
||||
pIfRow.dwIndex = structure.dwIndex;
|
||||
if (GetIfEntry(ref pIfRow) == 0)
|
||||
{
|
||||
var str = Encoding.ASCII.GetString(structure.bDescr, 0, pIfRow.dwDescrLen - 1);
|
||||
foreach (var networkInterface in networkInterfaces)
|
||||
{
|
||||
if (networkInterface.Description == str)
|
||||
{
|
||||
_adapters.Add(structure.dwIndex, networkInterface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(MIB_IFROW)));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(num1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct MIB_IPFORWARDROW
|
||||
{
|
||||
public uint dwForwardDest;
|
||||
public uint dwForwardMask;
|
||||
public int dwForwardPolicy;
|
||||
public uint dwForwardNextHop;
|
||||
public int dwForwardIfIndex;
|
||||
public ForwardType dwForwardType;
|
||||
public ForwardProtocol dwForwardProto;
|
||||
public int dwForwardAge;
|
||||
public int dwForwardNextHopAS;
|
||||
public int dwForwardMetric1;
|
||||
public int dwForwardMetric2;
|
||||
public int dwForwardMetric3;
|
||||
public int dwForwardMetric4;
|
||||
public int dwForwardMetric5;
|
||||
|
||||
public static implicit operator MIB_IPFORWARDROW(RouteEntry value)
|
||||
{
|
||||
var mibIpforwardrow = new MIB_IPFORWARDROW();
|
||||
mibIpforwardrow.dwForwardAge = value.Age;
|
||||
mibIpforwardrow.dwForwardDest = BitConverter.ToUInt32(value.Destination.GetAddressBytes(), 0);
|
||||
mibIpforwardrow.dwForwardMask = BitConverter.ToUInt32(value.Mask.GetAddressBytes(), 0);
|
||||
mibIpforwardrow.dwForwardMetric1 = value.Metric1;
|
||||
mibIpforwardrow.dwForwardMetric2 = value.Metric2;
|
||||
mibIpforwardrow.dwForwardMetric3 = value.Metric3;
|
||||
mibIpforwardrow.dwForwardMetric4 = value.Metric4;
|
||||
mibIpforwardrow.dwForwardMetric5 = value.Metric5;
|
||||
mibIpforwardrow.dwForwardNextHop = BitConverter.ToUInt32(value.NextHop.GetAddressBytes(), 0);
|
||||
mibIpforwardrow.dwForwardNextHopAS = value.NextHopAS;
|
||||
mibIpforwardrow.dwForwardPolicy = value.Policy;
|
||||
mibIpforwardrow.dwForwardProto = value.Protocol;
|
||||
mibIpforwardrow.dwForwardType = value.ForwardType;
|
||||
var adaptersTable = new AdaptersTable();
|
||||
mibIpforwardrow.dwForwardIfIndex = adaptersTable.GetAdapterIndex(value.RelatedInterface);
|
||||
return mibIpforwardrow;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("iphlpapi", SetLastError = true)]
|
||||
public static extern int GetIfTable(IntPtr pIfTable, ref int pdwSize, bool bOrder);
|
||||
|
||||
[DllImport("iphlpapi", SetLastError = true)]
|
||||
public static extern int GetIfEntry(ref MIB_IFROW pIfRow);
|
||||
|
||||
[DllImport("iphlpapi", SetLastError = true)]
|
||||
public static extern int GetBestRoute(uint dwDestAddr, int dwSourceAddr, out MIB_IPFORWARDROW pRoute);
|
||||
|
||||
[DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
public static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("WinINet")]
|
||||
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user