Compare commits

...

36 Commits

Author SHA1 Message Date
ChsBuffer
5836f87537 bump version to 1.6.0-Beta1 2020-09-30 18:31:01 +08:00
ChsBuffer
12780e5116 fix a typo 2020-09-28 16:48:56 +08:00
ChsBuffer
ecd1257a35 Refactoring InitText 2020-09-27 13:01:44 +08:00
ChsBuffer
49e2eb6a56 fix a typo 2020-09-26 16:32:30 +08:00
ChsBuffer
8ee86c3996 add Global.Flags 2020-09-26 16:02:35 +08:00
ChsBuffer
9b12ae9462 Refactoring 2020-09-26 15:00:18 +08:00
ChsBuffer
801e8e3b8a Use GetLocalEndPoint to replace GetBestRoute 2020-09-25 01:19:15 +08:00
ChsBuffer
74f136bd93 Fix HTTP port information lost 2020-09-24 19:21:13 +08:00
ChsBuffer
e9a1750871 Refactor LoadProfile 2020-09-22 23:15:13 +08:00
ChsBuffer
626192c5ea detach find ManagementObject method,Fix ICS checkbox not displaying status correctly 2020-09-22 22:42:15 +08:00
ChsBuffer
8b7ce23a82 Add TAP Adapter Internet Network Sharing Setting(ICS) 2020-09-22 17:57:26 +08:00
AmazingDM
48d543ce65 update driver 2020-09-22 11:26:08 +08:00
ChsBuffer
dbc45a2562 update tun2socks.exe to v1.16.11 2020-09-21 21:47:14 +08:00
ChsBuffer
b3f8b863e2 Check whether tun2socks supports fakeDNS 2020-09-21 21:27:54 +08:00
ChsBuffer
becc6d8187 rename ClearBypass() to ClearRouteTable() 2020-09-21 21:27:37 +08:00
ChsBuffer
f777fae3d8 Use the registry to edit System DNS instead of WMI, check network connection before start mode 2020-09-19 19:05:12 +08:00
ChsBuffer
383efc453d update PostBuild.bat 2020-09-19 10:57:41 +08:00
AmazingDM
83096c3f11 Update Advanced_Usage.zh-CN.md 2020-09-19 01:54:35 +08:00
ChsBuffer
e8c1bcb74b replace unbound dns with aiodns 2020-09-18 20:41:21 +08:00
ChsBuffer
76aa32967f Fix ModeComboBoxSelectedIndex save incorrectly 2020-09-18 19:35:20 +08:00
Connection Refused
082803469d Update modes 2020-09-18 18:31:43 +08:00
Connection Refused
7d47122b37 Update README.md 2020-09-18 18:30:38 +08:00
Connection Refused
27f4768f24 Update modes 2020-09-18 18:29:25 +08:00
ChsBuffer
9f4a974a3c Remove MainForm.State setter thread safety check 2020-09-10 17:10:37 +08:00
ChsBuffer
a89efdb0d7 简化NTT控制器返回值 2020-09-10 17:04:17 +08:00
ChsBuffer
04fd88ea3c 优化SearchComboBox 2020-09-10 17:04:17 +08:00
AmazingDM
c9527e8671 添加FAQ 2020-09-09 15:59:35 +08:00
ChsBuffer
5a431710ad 简化主控制器 2020-09-07 14:38:01 +08:00
ChsBuffer
c305473793 fix a typo 2020-09-06 23:41:19 +08:00
ChsBuffer
c4f06eb45d 适配新Redirector 2020-09-06 23:37:32 +08:00
Connection Refused
664cff4e52 Use new Redirector 2020-09-06 19:41:23 +08:00
ChsBuffer
20990e537c Optimize 'using' directives 2020-09-06 14:20:18 +08:00
ChsBuffer
1d33dda9bc 整理方法归属 2020-09-06 13:53:56 +08:00
ChsBuffer
116d5418d1 整理 SettingForm 2020-09-06 13:25:12 +08:00
Connection Refused
cdaa1fbc25 Add Sponsor (JetBrains) 2020-09-05 01:37:58 +08:00
ChsBuffer
7458b7b4cd 完善更新过程对非.zip压缩包支持 2020-09-04 15:19:19 +08:00
107 changed files with 3745 additions and 3418 deletions

43
.github/jetbrains-variant-4.svg vendored Normal file
View 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

View File

@@ -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
}
}

View File

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

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

View File

@@ -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)
{

View File

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

View File

@@ -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
{
}
}

View File

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

View File

@@ -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
}
}

View File

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

View File

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

View File

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

View File

@@ -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

View File

@@ -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)

View File

@@ -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());

View File

@@ -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;

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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)
{

View File

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

View File

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

View File

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

View File

@@ -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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;

View File

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

View File

@@ -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();

View File

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

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

View File

@@ -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>
/// 用户 IDV2
/// </summary>
public string UserID = string.Empty;
/// <summary>
/// 额外 IDV2
/// </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>
/// 伪装域名V2HTTP、WebSocket、HTTP/2
/// </summary>
public string Host = string.Empty;
/// <summary>
/// 传输路径V2WebSocket、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;
}
}

View File

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

View File

@@ -1,8 +1,5 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Netch.Utils;
namespace Netch.Models
{

View File

@@ -1,16 +0,0 @@
namespace Netch.Models
{
public class STUN_Client
{
public enum NatType
{
UdpBlocked,
OpenInternet,
SymmetricUdpFirewall,
FullCone,
RestrictedCone,
PortRestrictedCone,
Symmetric
}
}
}

View File

@@ -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>
/// 用户 IDVMess
/// </summary>
public string UserID = string.Empty;
/// <summary>
/// 额外 IDVMess
/// </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>
/// 伪装域名VMessHTTP、WebSocket、HTTP/2
/// </summary>
public string Host = string.Empty;
/// <summary>
/// 传输路径VMessWebSocket、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;

View File

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

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.ComponentModel;
namespace Netch.Models
{

View 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];
}
}
}

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

View File

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

View File

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

View File

@@ -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>

View File

@@ -1,10 +0,0 @@
namespace Netch.Override
{
public class ToolStripProfessionalRender : System.Windows.Forms.ToolStripProfessionalRenderer
{
protected override void OnRenderToolStripBorder(System.Windows.Forms.ToolStripRenderEventArgs e)
{
// ignored
}
}
}

View File

@@ -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

View File

@@ -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")]

View File

@@ -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": "赞助商",

View File

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

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

View File

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

View File

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

View File

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

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

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

View 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"
};
}
}

View File

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

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

View File

@@ -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();

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

View 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"
};
}
}

View File

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

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

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

View 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";
}
}
}

View File

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

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

View File

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

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

View File

@@ -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,

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

View File

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

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

View File

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

View File

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

View 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"
};
}
}

View File

@@ -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>

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

View File

@@ -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)
{

View File

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

View File

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

View File

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

View File

@@ -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"
};

View File

@@ -4,7 +4,7 @@ using Netch.Models;
namespace Netch.Utils
{
class MessageBoxX
static class MessageBoxX
{
/// <summary>
/// </summary>

View File

@@ -12,7 +12,7 @@ namespace Netch.Utils
Show,
Exit
}
public static event EventHandler<Commands> Called;
private static void OnCalled(Commands e)

View File

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

View File

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

View File

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

View File

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

View File

@@ -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>
/// 异步下载

View File

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

View File

@@ -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