mirror of
https://github.com/netchx/netch.git
synced 2026-03-14 17:43:18 +08:00
Add files via upload
This commit is contained in:
3
Netch/.gitignore
vendored
Normal file
3
Netch/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/bin
|
||||
/obj
|
||||
/*.csproj.user
|
||||
24
Netch/App.manifest
Normal file
24
Netch/App.manifest
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="Netch"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
9
Netch/App.xaml
Normal file
9
Netch/App.xaml
Normal file
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="Netch.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Netch"
|
||||
Startup="Application_Startup">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
13
Netch/App.xaml.cs
Normal file
13
Netch/App.xaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
private void Application_Startup(object sender, StartupEventArgs e)
|
||||
{
|
||||
this.MainWindow = new Forms.MainWindow();
|
||||
this.MainWindow.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Netch/AssemblyInfo.cs
Normal file
10
Netch/AssemblyInfo.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
9
Netch/Controllers/Interface/IController.cs
Normal file
9
Netch/Controllers/Interface/IController.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Netch.Controllers.Interface
|
||||
{
|
||||
public interface IController
|
||||
{
|
||||
bool Create(Models.Server.Server s, Models.Mode.Mode m);
|
||||
|
||||
bool Delete();
|
||||
}
|
||||
}
|
||||
108
Netch/Controllers/MainController.cs
Normal file
108
Netch/Controllers/MainController.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class MainController : Interface.IController
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点控制器
|
||||
/// </summary>
|
||||
private Interface.IController NodeController;
|
||||
|
||||
/// <summary>
|
||||
/// 模式控制器
|
||||
/// </summary>
|
||||
private Interface.IController ModeController;
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
switch (s.Type)
|
||||
{
|
||||
case Models.Server.ServerType.Socks:
|
||||
break;
|
||||
case Models.Server.ServerType.Shadowsocks:
|
||||
{
|
||||
if (m.Type == Models.Mode.ModeType.ProcessMode)
|
||||
{
|
||||
var node = s as Models.Server.Shadowsocks.Shadowsocks;
|
||||
if (String.IsNullOrEmpty(node.OBFS))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.NodeController = new Server.SSController();
|
||||
}
|
||||
break;
|
||||
case Models.Server.ServerType.ShadowsocksR:
|
||||
this.NodeController = new Server.SRController();
|
||||
break;
|
||||
case Models.Server.ServerType.Trojan:
|
||||
this.NodeController = new Server.TRController();
|
||||
break;
|
||||
case Models.Server.ServerType.VLess:
|
||||
this.NodeController = new Server.VLController();
|
||||
break;
|
||||
case Models.Server.ServerType.VMess:
|
||||
this.NodeController = new Server.VMController();
|
||||
break;
|
||||
default:
|
||||
Global.Logger.Error($"未知的节点类型:{s.Type}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
var status = this.NodeController?.Create(s, m);
|
||||
if (status.HasValue && !status.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m.Type)
|
||||
{
|
||||
case Models.Mode.ModeType.ProcessMode:
|
||||
this.ModeController = new Mode.ProcessController();
|
||||
break;
|
||||
case Models.Mode.ModeType.ShareMode:
|
||||
this.ModeController = new Mode.ShareController();
|
||||
break;
|
||||
case Models.Mode.ModeType.TapMode:
|
||||
this.ModeController = new Mode.TapController();
|
||||
break;
|
||||
case Models.Mode.ModeType.TunMode:
|
||||
this.ModeController = new Mode.TunController();
|
||||
break;
|
||||
case Models.Mode.ModeType.WebMode:
|
||||
this.ModeController = new Mode.WebController();
|
||||
break;
|
||||
case Models.Mode.ModeType.WmpMode:
|
||||
this.ModeController = new Mode.WmpController();
|
||||
break;
|
||||
default:
|
||||
Global.Logger.Error($"未知的模式类型:{s.Type}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
var status = this.ModeController?.Create(s, m);
|
||||
if (status.HasValue && !status.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
this.NodeController?.Delete();
|
||||
this.ModeController?.Delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Netch/Controllers/Mode/ProcessController.cs
Normal file
136
Netch/Controllers/Mode/ProcessController.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Controllers.Mode
|
||||
{
|
||||
public class ProcessController : Interface.IController
|
||||
{
|
||||
private enum NameList : int
|
||||
{
|
||||
TYPE_FILTERLOOPBACK,
|
||||
TYPE_FILTERTCP,
|
||||
TYPE_FILTERUDP,
|
||||
TYPE_CLRNAME,
|
||||
TYPE_ADDNAME,
|
||||
TYPE_BYPNAME,
|
||||
TYPE_DNSHOST,
|
||||
TYPE_TCPLISN,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
TYPE_UDPLISN,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
}
|
||||
|
||||
private static class Methods
|
||||
{
|
||||
[DllImport("Redirector.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aio_dial(NameList 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();
|
||||
}
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
var mode = m as Models.Mode.ProcessMode.ProcessMode;
|
||||
Methods.aio_dial(NameList.TYPE_FILTERLOOPBACK, mode.Loopback ? "true" : "false");
|
||||
Methods.aio_dial(NameList.TYPE_FILTERTCP, mode.TCP ? "true" : "false");
|
||||
Methods.aio_dial(NameList.TYPE_FILTERUDP, mode.UDP ? "true" : "false");
|
||||
|
||||
Methods.aio_dial(NameList.TYPE_CLRNAME, "");
|
||||
Methods.aio_dial(NameList.TYPE_BYPNAME, AppDomain.CurrentDomain.BaseDirectory.Replace("\\", "\\\\"));
|
||||
for (int i = 0; i < mode.HandleList.Count; i++) if (!Methods.aio_dial(NameList.TYPE_ADDNAME, mode.HandleList[i])) return false;
|
||||
for (int i = 0; i < mode.BypassList.Count; i++) if (!Methods.aio_dial(NameList.TYPE_BYPNAME, mode.BypassList[i])) return false;
|
||||
|
||||
Methods.aio_dial(NameList.TYPE_TCPLISN, Global.Config.Ports.Redir.ToString());
|
||||
Methods.aio_dial(NameList.TYPE_UDPLISN, Global.Config.Ports.Redir.ToString());
|
||||
|
||||
switch (s.Type)
|
||||
{
|
||||
case Models.Server.ServerType.Socks:
|
||||
{
|
||||
var node = s as Models.Server.Socks.Socks;
|
||||
Methods.aio_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.aio_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.aio_dial(NameList.TYPE_TCPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
Methods.aio_dial(NameList.TYPE_UDPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
|
||||
if (!String.IsNullOrEmpty(node.Username))
|
||||
{
|
||||
Methods.aio_dial(NameList.TYPE_TCPUSER, node.Username);
|
||||
Methods.aio_dial(NameList.TYPE_UDPUSER, node.Username);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(node.Password))
|
||||
{
|
||||
Methods.aio_dial(NameList.TYPE_TCPPASS, node.Password);
|
||||
Methods.aio_dial(NameList.TYPE_UDPPASS, node.Password);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Models.Server.ServerType.Shadowsocks:
|
||||
{
|
||||
var node = s as Models.Server.Shadowsocks.Shadowsocks;
|
||||
if (String.IsNullOrEmpty(node.OBFS))
|
||||
{
|
||||
Methods.aio_dial(NameList.TYPE_TCPTYPE, "Shadowsocks");
|
||||
Methods.aio_dial(NameList.TYPE_UDPTYPE, "Shadowsocks");
|
||||
Methods.aio_dial(NameList.TYPE_TCPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
Methods.aio_dial(NameList.TYPE_UDPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
Methods.aio_dial(NameList.TYPE_TCPPASS, node.Passwd);
|
||||
Methods.aio_dial(NameList.TYPE_UDPPASS, node.Passwd);
|
||||
Methods.aio_dial(NameList.TYPE_TCPMETH, node.Method);
|
||||
Methods.aio_dial(NameList.TYPE_UDPMETH, node.Method);
|
||||
}
|
||||
else
|
||||
{
|
||||
Methods.aio_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.aio_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.aio_dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
Methods.aio_dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
Methods.aio_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.aio_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.aio_dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
Methods.aio_dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Methods.aio_init();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
return Methods.aio_free();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Mode/ShareController.cs
Normal file
15
Netch/Controllers/Mode/ShareController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Controllers.Mode
|
||||
{
|
||||
public class ShareController : Interface.IController
|
||||
{
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
235
Netch/Controllers/Mode/TapController.cs
Normal file
235
Netch/Controllers/Mode/TapController.cs
Normal file
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Controllers.Mode
|
||||
{
|
||||
public class TapController : Interface.IController
|
||||
{
|
||||
private enum NameList : int
|
||||
{
|
||||
TYPE_BYPBIND,
|
||||
TYPE_BYPLIST,
|
||||
TYPE_DNSADDR,
|
||||
TYPE_ADAPMTU,
|
||||
TYPE_TCPREST,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
TYPE_UDPREST,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
}
|
||||
|
||||
private static class Methods
|
||||
{
|
||||
[DllImport("tap2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool tap_dial(NameList name, string value);
|
||||
|
||||
[DllImport("tap2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool tap_init();
|
||||
|
||||
[DllImport("tap2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool tap_free();
|
||||
|
||||
[DllImport("tap2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern string tap_name();
|
||||
|
||||
[DllImport("tap2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tap_getUP();
|
||||
|
||||
[DllImport("tap2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tap_getDL();
|
||||
}
|
||||
|
||||
private Tools.TunTap.Outbound Outbound = new();
|
||||
private Interface.IController DNSController;
|
||||
|
||||
private bool AssignInterface()
|
||||
{
|
||||
var index = Utils.RouteHelper.GetInterfaceIndexByDescription(Methods.tap_name());
|
||||
|
||||
var address = Global.Config.TunMode.Network.Split('/')[0];
|
||||
var netmask = byte.Parse(Global.Config.TunMode.Network.Split('/')[1]);
|
||||
if (!Utils.RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork, address, netmask, index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NetworkInterface adapter = Utils.RouteHelper.GetInterfaceByIndex(index);
|
||||
if (adapter == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (var wmi = new ManagementClass("Win32_NetworkAdapterConfiguration"))
|
||||
{
|
||||
using var ins = wmi.GetInstances();
|
||||
var ada = ins.Cast<ManagementObject>().First(m => m["Description"].ToString() == adapter.Description);
|
||||
|
||||
var dns = new[] { "127.0.0.1" };
|
||||
if (Global.Config.TunMode.DNS != "aiodns")
|
||||
{
|
||||
dns[0] = Global.Config.TunMode.DNS;
|
||||
}
|
||||
|
||||
using var ord = wmi.GetMethodParameters("SetDNSServerSearchOrder");
|
||||
ord["DNSServerSearchOrder"] = dns;
|
||||
|
||||
ada.InvokeMethod("SetDNSServerSearchOrder", ord, null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CreateServerRoute(Models.Server.Server s)
|
||||
{
|
||||
var addr = Utils.DNS.Fetch(s.Host);
|
||||
if (addr == IPAddress.Any)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addr.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Utils.RouteHelper.CreateRoute(AddressFamily.InterNetwork, addr.ToString(), 32, this.Outbound.Gateway.ToString(), this.Outbound.Index);
|
||||
}
|
||||
|
||||
private bool CreateHandleRoute(Models.Mode.TunMode.TunMode mode)
|
||||
{
|
||||
var index = Utils.RouteHelper.GetInterfaceIndexByDescription(Methods.tap_name());
|
||||
|
||||
for (int i = 0; i < mode.HandleList.Count; i++)
|
||||
{
|
||||
var address = mode.HandleList[i].Split('/')[0];
|
||||
var netmask = byte.Parse(mode.HandleList[i].Split('/')[1]);
|
||||
|
||||
Utils.RouteHelper.CreateRoute(AddressFamily.InterNetwork, address, netmask, Global.Config.TunMode.Gateway, index);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
if (!this.Outbound.Get())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Methods.tap_dial(NameList.TYPE_BYPBIND, this.Outbound.Address.ToString());
|
||||
|
||||
var mode = m as Models.Mode.TunMode.TunMode;
|
||||
if (mode.BypassList.Count > 0)
|
||||
{
|
||||
if (File.Exists("ipcidr.txt"))
|
||||
{
|
||||
File.Delete("ipcidr.txt");
|
||||
}
|
||||
File.WriteAllLines("ipcidr.txt", mode.BypassList);
|
||||
|
||||
Methods.tap_dial(NameList.TYPE_BYPLIST, "ipcidr.txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
Methods.tap_dial(NameList.TYPE_BYPLIST, "disabled");
|
||||
}
|
||||
|
||||
Methods.tap_dial(NameList.TYPE_DNSADDR, (Global.Config.TunMode.DNS == "aiodns") ? "127.0.0.1" : Global.Config.TunMode.DNS);
|
||||
Methods.tap_dial(NameList.TYPE_TCPREST, "");
|
||||
Methods.tap_dial(NameList.TYPE_UDPREST, "");
|
||||
|
||||
switch (s.Type)
|
||||
{
|
||||
case Models.Server.ServerType.Socks:
|
||||
{
|
||||
var node = s as Models.Server.Socks.Socks;
|
||||
|
||||
Methods.tap_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.tap_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.tap_dial(NameList.TYPE_TCPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
Methods.tap_dial(NameList.TYPE_UDPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
|
||||
if (!String.IsNullOrEmpty(node.Username))
|
||||
{
|
||||
Methods.tap_dial(NameList.TYPE_TCPUSER, node.Username);
|
||||
Methods.tap_dial(NameList.TYPE_UDPUSER, node.Username);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(node.Password))
|
||||
{
|
||||
Methods.tap_dial(NameList.TYPE_TCPPASS, node.Password);
|
||||
Methods.tap_dial(NameList.TYPE_UDPPASS, node.Password);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Methods.tap_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.tap_dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
Methods.tap_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.tap_dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Methods.tap_init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.DNSController = new Other.DNS.AioDNSController();
|
||||
if (!this.DNSController.Create(s, m))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.AssignInterface())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.CreateServerRoute(s))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.CreateHandleRoute(mode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (File.Exists("ipcidr.txt"))
|
||||
{
|
||||
File.Delete("ipcidr.txt");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
this.DNSController?.Delete();
|
||||
|
||||
return Methods.tap_free();
|
||||
}
|
||||
}
|
||||
}
|
||||
235
Netch/Controllers/Mode/TunController.cs
Normal file
235
Netch/Controllers/Mode/TunController.cs
Normal file
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Controllers.Mode
|
||||
{
|
||||
public class TunController : Interface.IController
|
||||
{
|
||||
private enum NameList : int
|
||||
{
|
||||
TYPE_BYPBIND,
|
||||
TYPE_BYPLIST,
|
||||
TYPE_DNSADDR,
|
||||
TYPE_ADAPMTU,
|
||||
TYPE_TCPREST,
|
||||
TYPE_TCPTYPE,
|
||||
TYPE_TCPHOST,
|
||||
TYPE_TCPUSER,
|
||||
TYPE_TCPPASS,
|
||||
TYPE_TCPMETH,
|
||||
TYPE_TCPPROT,
|
||||
TYPE_TCPPRPA,
|
||||
TYPE_TCPOBFS,
|
||||
TYPE_TCPOBPA,
|
||||
TYPE_UDPREST,
|
||||
TYPE_UDPTYPE,
|
||||
TYPE_UDPHOST,
|
||||
TYPE_UDPUSER,
|
||||
TYPE_UDPPASS,
|
||||
TYPE_UDPMETH,
|
||||
TYPE_UDPPROT,
|
||||
TYPE_UDPPRPA,
|
||||
TYPE_UDPOBFS,
|
||||
TYPE_UDPOBPA
|
||||
}
|
||||
|
||||
private static class Methods
|
||||
{
|
||||
[DllImport("tun2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool tun_dial(NameList name, string value);
|
||||
|
||||
[DllImport("tun2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool tun_init();
|
||||
|
||||
[DllImport("tun2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool tun_free();
|
||||
|
||||
[DllImport("tun2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tun_luid();
|
||||
|
||||
[DllImport("tun2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tun_getUP();
|
||||
|
||||
[DllImport("tun2socks.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong tun_getDL();
|
||||
}
|
||||
|
||||
private Tools.TunTap.Outbound Outbound = new();
|
||||
private Interface.IController DNSController;
|
||||
|
||||
private bool AssignInterface()
|
||||
{
|
||||
var index = Utils.RouteHelper.ConvertLuidToIndex(Methods.tun_luid());
|
||||
|
||||
var address = Global.Config.TunMode.Network.Split('/')[0];
|
||||
var netmask = byte.Parse(Global.Config.TunMode.Network.Split('/')[1]);
|
||||
if (!Utils.RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork, address, netmask, index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NetworkInterface adapter = Utils.RouteHelper.GetInterfaceByIndex(index);
|
||||
if (adapter == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (var wmi = new ManagementClass("Win32_NetworkAdapterConfiguration"))
|
||||
{
|
||||
using var ins = wmi.GetInstances();
|
||||
var ada = ins.Cast<ManagementObject>().First(m => m["Description"].ToString() == adapter.Description);
|
||||
|
||||
var dns = new[] { "127.0.0.1" };
|
||||
if (Global.Config.TunMode.DNS != "aiodns")
|
||||
{
|
||||
dns[0] = Global.Config.TunMode.DNS;
|
||||
}
|
||||
|
||||
using var ord = wmi.GetMethodParameters("SetDNSServerSearchOrder");
|
||||
ord["DNSServerSearchOrder"] = dns;
|
||||
|
||||
ada.InvokeMethod("SetDNSServerSearchOrder", ord, null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CreateServerRoute(Models.Server.Server s)
|
||||
{
|
||||
var addr = Utils.DNS.Fetch(s.Host);
|
||||
if (addr == IPAddress.Any)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addr.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Utils.RouteHelper.CreateRoute(AddressFamily.InterNetwork, addr.ToString(), 32, this.Outbound.Gateway.ToString(), this.Outbound.Index);
|
||||
}
|
||||
|
||||
private bool CreateHandleRoute(Models.Mode.TunMode.TunMode mode)
|
||||
{
|
||||
var index = Utils.RouteHelper.ConvertLuidToIndex(Methods.tun_luid());
|
||||
|
||||
for (int i = 0; i < mode.HandleList.Count; i++)
|
||||
{
|
||||
var address = mode.HandleList[i].Split('/')[0];
|
||||
var netmask = byte.Parse(mode.HandleList[i].Split('/')[1]);
|
||||
|
||||
Utils.RouteHelper.CreateRoute(AddressFamily.InterNetwork, address, netmask, Global.Config.TunMode.Gateway, index);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
if (!this.Outbound.Get())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Methods.tun_dial(NameList.TYPE_BYPBIND, this.Outbound.Address.ToString());
|
||||
|
||||
var mode = m as Models.Mode.TunMode.TunMode;
|
||||
if (mode.BypassList.Count > 0)
|
||||
{
|
||||
if (File.Exists("ipcidr.txt"))
|
||||
{
|
||||
File.Delete("ipcidr.txt");
|
||||
}
|
||||
File.WriteAllLines("ipcidr.txt", mode.BypassList);
|
||||
|
||||
Methods.tun_dial(NameList.TYPE_BYPLIST, "ipcidr.txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
Methods.tun_dial(NameList.TYPE_BYPLIST, "disabled");
|
||||
}
|
||||
|
||||
Methods.tun_dial(NameList.TYPE_DNSADDR, (Global.Config.TunMode.DNS == "aiodns") ? "127.0.0.1" : Global.Config.TunMode.DNS);
|
||||
Methods.tun_dial(NameList.TYPE_TCPREST, "");
|
||||
Methods.tun_dial(NameList.TYPE_UDPREST, "");
|
||||
|
||||
switch (s.Type)
|
||||
{
|
||||
case Models.Server.ServerType.Socks:
|
||||
{
|
||||
var node = s as Models.Server.Socks.Socks;
|
||||
|
||||
Methods.tun_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.tun_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.tun_dial(NameList.TYPE_TCPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
Methods.tun_dial(NameList.TYPE_UDPHOST, $"{node.Resolve()}:{node.Port}");
|
||||
|
||||
if (!String.IsNullOrEmpty(node.Username))
|
||||
{
|
||||
Methods.tun_dial(NameList.TYPE_TCPUSER, node.Username);
|
||||
Methods.tun_dial(NameList.TYPE_UDPUSER, node.Username);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(node.Password))
|
||||
{
|
||||
Methods.tun_dial(NameList.TYPE_TCPPASS, node.Password);
|
||||
Methods.tun_dial(NameList.TYPE_UDPPASS, node.Password);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Methods.tun_dial(NameList.TYPE_TCPTYPE, "Socks");
|
||||
Methods.tun_dial(NameList.TYPE_TCPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
Methods.tun_dial(NameList.TYPE_UDPTYPE, "Socks");
|
||||
Methods.tun_dial(NameList.TYPE_UDPHOST, $"127.0.0.1:{Global.Config.Ports.Socks}");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Methods.tun_init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.DNSController = new Other.DNS.AioDNSController();
|
||||
if (!this.DNSController.Create(s, m))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.AssignInterface())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.CreateServerRoute(s))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.CreateHandleRoute(mode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (File.Exists("ipcidr.txt"))
|
||||
{
|
||||
File.Delete("ipcidr.txt");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
this.DNSController?.Delete();
|
||||
|
||||
return Methods.tun_free();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Mode/WebController.cs
Normal file
15
Netch/Controllers/Mode/WebController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Controllers.Mode
|
||||
{
|
||||
public class WebController : Interface.IController
|
||||
{
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Mode/WmpController.cs
Normal file
15
Netch/Controllers/Mode/WmpController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Controllers.Mode
|
||||
{
|
||||
public class WmpController : Interface.IController
|
||||
{
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Netch/Controllers/Other/DNS/AioDNSController.cs
Normal file
46
Netch/Controllers/Other/DNS/AioDNSController.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Controllers.Other.DNS
|
||||
{
|
||||
public class AioDNSController : Interface.IController
|
||||
{
|
||||
private enum NameList : int
|
||||
{
|
||||
TYPE_REST,
|
||||
TYPE_ADDR,
|
||||
TYPE_LIST,
|
||||
TYPE_CDNS,
|
||||
TYPE_ODNS
|
||||
}
|
||||
|
||||
private static class Methods
|
||||
{
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_dial(NameList name, string value);
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool aiodns_init();
|
||||
|
||||
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void aiodns_free();
|
||||
}
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
Methods.aiodns_dial(NameList.TYPE_REST, "");
|
||||
Methods.aiodns_dial(NameList.TYPE_ADDR, ":53");
|
||||
Methods.aiodns_dial(NameList.TYPE_LIST, "Bin\\aiodns.conf");
|
||||
Methods.aiodns_dial(NameList.TYPE_CDNS, Global.Config.AioDNS.ChinaDNS);
|
||||
Methods.aiodns_dial(NameList.TYPE_ODNS, Global.Config.AioDNS.OtherDNS);
|
||||
|
||||
return Methods.aiodns_init();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
Methods.aiodns_free();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Netch/Controllers/Server/SRController.cs
Normal file
53
Netch/Controllers/Server/SRController.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Controllers.Server
|
||||
{
|
||||
public class SRController : Interface.IController
|
||||
{
|
||||
private Tools.Guard Guard = new()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin\\ShadowsocksR.exe"),
|
||||
WorkingDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin"),
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
},
|
||||
JudgmentStarted = new List<string>()
|
||||
{
|
||||
"listening at"
|
||||
},
|
||||
JudgmentStopped = new List<string>()
|
||||
{
|
||||
"usage",
|
||||
"invalid"
|
||||
},
|
||||
AutoRestart = true
|
||||
};
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
var node = s as Models.Server.ShadowsocksR.ShadowsocksR;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"-l {Global.Config.Ports.Socks} -s {node.Resolve()} -p {node.Port} -k '{node.Passwd}' -O {node.Prot} -o {node.OBFS} -t 30 -u --fast-open --no-delay");
|
||||
if (!String.IsNullOrEmpty(node.ProtParam)) sb.Append($" -G '{node.ProtParam}'");
|
||||
if (!String.IsNullOrEmpty(node.OBFSParam)) sb.Append($" -g '{node.OBFSParam}'");
|
||||
|
||||
this.Guard.StartInfo.Arguments = sb.ToString();
|
||||
return this.Guard.Create();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
this.Guard.Delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Netch/Controllers/Server/SSController.cs
Normal file
53
Netch/Controllers/Server/SSController.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Controllers.Server
|
||||
{
|
||||
public class SSController : Interface.IController
|
||||
{
|
||||
private Tools.Guard Guard = new()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin\\Shadowsocks.exe"),
|
||||
WorkingDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin"),
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
},
|
||||
JudgmentStarted = new List<string>()
|
||||
{
|
||||
"listening at"
|
||||
},
|
||||
JudgmentStopped = new List<string>()
|
||||
{
|
||||
"usage",
|
||||
"invalid",
|
||||
"plugin service exit unexpectedly"
|
||||
},
|
||||
AutoRestart = true
|
||||
};
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
var node = s as Models.Server.Shadowsocks.Shadowsocks;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"-l {Global.Config.Ports.Socks} -s {node.Resolve()} -p {node.Port} -k '{node.Passwd}' -t 30 -u --fast-open --no-delay");
|
||||
if (!String.IsNullOrEmpty(node.OBFS)) sb.Append($" --plugin '{node.OBFS}' --plugin-opts '{node.OBFSParam}'");
|
||||
|
||||
this.Guard.StartInfo.Arguments = sb.ToString();
|
||||
return this.Guard.Create();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
this.Guard.Delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Server/TRController.cs
Normal file
15
Netch/Controllers/Server/TRController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Controllers.Server
|
||||
{
|
||||
public class TRController : Interface.IController
|
||||
{
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Server/VLController.cs
Normal file
15
Netch/Controllers/Server/VLController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Controllers.Server
|
||||
{
|
||||
public class VLController : Interface.IController
|
||||
{
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Netch/Controllers/Server/VMController.cs
Normal file
15
Netch/Controllers/Server/VMController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Controllers.Server
|
||||
{
|
||||
public class VMController : Interface.IController
|
||||
{
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Netch/Forms/MainWindow.xaml
Normal file
12
Netch/Forms/MainWindow.xaml
Normal file
@@ -0,0 +1,12 @@
|
||||
<Window x:Class="Netch.Forms.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Netch.Forms"
|
||||
mc:Ignorable="d"
|
||||
Title="Netch" Height="450" Width="800">
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
12
Netch/Forms/MainWindow.xaml.cs
Normal file
12
Netch/Forms/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Netch/Global.cs
Normal file
34
Netch/Global.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public static class Global
|
||||
{
|
||||
/// <summary>
|
||||
/// 版本号
|
||||
/// </summary>
|
||||
public static readonly string VerCode = "2.0.0";
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录
|
||||
/// </summary>
|
||||
public static Tools.Logger Logger = new Tools.Logger() { SavePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs\\Netch.log") };
|
||||
|
||||
/// <summary>
|
||||
/// 配置文件
|
||||
/// </summary>
|
||||
public static Models.Config.Config Config;
|
||||
|
||||
/// <summary>
|
||||
/// 节点列表
|
||||
/// </summary>
|
||||
public static List<Models.Server.ServerList> NodeList;
|
||||
|
||||
/// <summary>
|
||||
/// 模式列表
|
||||
/// </summary>
|
||||
public static List<Models.Mode.Mode> ModeList;
|
||||
}
|
||||
}
|
||||
15
Netch/Models/Config/AioDNS.cs
Normal file
15
Netch/Models/Config/AioDNS.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class AioDNS
|
||||
{
|
||||
/// <summary>
|
||||
/// 国内 DNS 地址
|
||||
/// </summary>
|
||||
public string ChinaDNS = "tcp://119.29.29.29:53";
|
||||
|
||||
/// <summary>
|
||||
/// 国外 DNS 地址
|
||||
/// </summary>
|
||||
public string OtherDNS = "tls://1.1.1.1:853";
|
||||
}
|
||||
}
|
||||
73
Netch/Models/Config/Config.cs
Normal file
73
Netch/Models/Config/Config.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class Config
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置 版本
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("verCode")]
|
||||
public int VerCode = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 通用 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("generic")]
|
||||
public Generic Generic = new();
|
||||
|
||||
/// <summary>
|
||||
/// 端口 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("ports")]
|
||||
public Ports Ports = new();
|
||||
|
||||
/// <summary>
|
||||
/// ProcessMode 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("processmode")]
|
||||
public ProcessMode ProcessMode = new();
|
||||
|
||||
/// <summary>
|
||||
/// ShareMode 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("sharemode")]
|
||||
public ShareMode ShareMode = new();
|
||||
|
||||
/// <summary>
|
||||
/// TapMode 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("tapmode")]
|
||||
public TapMode TapMode = new();
|
||||
|
||||
/// <summary>
|
||||
/// TunMode 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("tunmode")]
|
||||
public TunMode TunMode = new();
|
||||
|
||||
/// <summary>
|
||||
/// AioDNS 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("aiodns")]
|
||||
public AioDNS AioDNS = new();
|
||||
|
||||
/// <summary>
|
||||
/// V2Ray 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("v2ray")]
|
||||
public V2Ray V2Ray = new();
|
||||
|
||||
/// <summary>
|
||||
/// STUN 配置
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("stun")]
|
||||
public STUN STUN = new();
|
||||
|
||||
/// <summary>
|
||||
/// 订阅链接
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("subscriptions")]
|
||||
public List<Subscription> Subscriptions = new();
|
||||
}
|
||||
}
|
||||
15
Netch/Models/Config/Generic.cs
Normal file
15
Netch/Models/Config/Generic.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// 检查 Unstable 更新
|
||||
/// </summary>
|
||||
public bool Unstable = false;
|
||||
|
||||
/// <summary>
|
||||
/// 使用 ICMP 测试延迟
|
||||
/// </summary>
|
||||
public bool ICMPing = true;
|
||||
}
|
||||
}
|
||||
23
Netch/Models/Config/Ports.cs
Normal file
23
Netch/Models/Config/Ports.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class Ports
|
||||
{
|
||||
/// <summary>
|
||||
/// Socks 端口
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("socks")]
|
||||
public int Socks = 2081;
|
||||
|
||||
/// <summary>
|
||||
/// Mixed 端口
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("mixed")]
|
||||
public int Mixed = 2082;
|
||||
|
||||
/// <summary>
|
||||
/// Redir 端口
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("redir")]
|
||||
public int Redir = 2083;
|
||||
}
|
||||
}
|
||||
11
Netch/Models/Config/ProcessMode.cs
Normal file
11
Netch/Models/Config/ProcessMode.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class ProcessMode
|
||||
{
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("dns")]
|
||||
public string DNS = "1.1.1.1:53";
|
||||
}
|
||||
}
|
||||
11
Netch/Models/Config/STUN.cs
Normal file
11
Netch/Models/Config/STUN.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class STUN
|
||||
{
|
||||
/// <summary>
|
||||
/// 主机名
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("host")]
|
||||
public string Host = "stun.ekiga.net";
|
||||
}
|
||||
}
|
||||
48
Netch/Models/Config/ShareMode.cs
Normal file
48
Netch/Models/Config/ShareMode.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class ShareMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 硬件地址(用于 ARP 回复)
|
||||
///
|
||||
/// CuteCR
|
||||
/// 43:75:74:65:43:52
|
||||
///
|
||||
/// NetchX
|
||||
/// 4e:65:74:63:68:58
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("hardware")]
|
||||
public string Hardware = "4e:65:74:63:68:58";
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("network")]
|
||||
public string Network = "100.64.0.0/24";
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("gateway")]
|
||||
public string Gateway = "100.64.0.1";
|
||||
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("dns")]
|
||||
public string DNS = "aiodns";
|
||||
|
||||
/// <summary>
|
||||
/// 网卡名(默认自动检测)
|
||||
/// </summary>
|
||||
public string EthernetName = "auto";
|
||||
|
||||
/// <summary>
|
||||
/// 绕过 IP 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassIPs = new();
|
||||
}
|
||||
}
|
||||
23
Netch/Models/Config/Subscription.cs
Normal file
23
Netch/Models/Config/Subscription.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class Subscription
|
||||
{
|
||||
/// <summary>
|
||||
/// 启用 / 禁用
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("enabled")]
|
||||
public bool Checked = true;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("remark")]
|
||||
public string Remark;
|
||||
|
||||
/// <summary>
|
||||
/// 链接
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("address")]
|
||||
public string Link;
|
||||
}
|
||||
}
|
||||
31
Netch/Models/Config/TapMode.cs
Normal file
31
Netch/Models/Config/TapMode.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class TapMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("network")]
|
||||
public string Network = "100.64.0.100/24";
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("gateway")]
|
||||
public string Gateway = "100.64.0.1";
|
||||
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("dns")]
|
||||
public string DNS = "aiodns";
|
||||
|
||||
/// <summary>
|
||||
/// 绕过 IP 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassIPs = new();
|
||||
}
|
||||
}
|
||||
31
Netch/Models/Config/TunMode.cs
Normal file
31
Netch/Models/Config/TunMode.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class TunMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("network")]
|
||||
public string Network = "100.64.0.100/24";
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("gateway")]
|
||||
public string Gateway = "100.64.0.1";
|
||||
|
||||
/// <summary>
|
||||
/// DNS
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("dns")]
|
||||
public string DNS = "aiodns";
|
||||
|
||||
/// <summary>
|
||||
/// 绕过 IP 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassIPs = new();
|
||||
}
|
||||
}
|
||||
63
Netch/Models/Config/V2Ray.cs
Normal file
63
Netch/Models/Config/V2Ray.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace Netch.Models.Config
|
||||
{
|
||||
public class V2Ray
|
||||
{
|
||||
/// <summary>
|
||||
/// FullCone 支持(需要 xray-core 服务端版本 v1.3.0+)
|
||||
/// </summary>
|
||||
public bool FullCone = false;
|
||||
|
||||
/// <summary>
|
||||
/// 跳过证书认证
|
||||
/// </summary>
|
||||
public bool Insecure = false;
|
||||
|
||||
/// <summary>
|
||||
/// 多路复用
|
||||
/// </summary>
|
||||
public bool Multiplex = false;
|
||||
|
||||
/// <summary>
|
||||
/// KCP 设定
|
||||
/// </summary>
|
||||
public V2RayKCP KCP = new();
|
||||
}
|
||||
|
||||
public class V2RayKCP
|
||||
{
|
||||
/// <summary>
|
||||
/// MTU
|
||||
/// </summary>
|
||||
public int MTU = 1450;
|
||||
|
||||
/// <summary>
|
||||
/// TTI
|
||||
/// </summary>
|
||||
public int TTI = 50;
|
||||
|
||||
/// <summary>
|
||||
/// 上行链路流量
|
||||
/// </summary>
|
||||
public int UPC = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 下行链路流量
|
||||
/// </summary>
|
||||
public int DLC = 20;
|
||||
|
||||
/// <summary>
|
||||
/// 读取缓冲区大小(MB)
|
||||
/// </summary>
|
||||
public int RBS = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 写入缓冲区大小(MB)
|
||||
/// </summary>
|
||||
public int WBS = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 拥塞控制
|
||||
/// </summary>
|
||||
public bool BBR = false;
|
||||
}
|
||||
}
|
||||
23
Netch/Models/GitHub/Asset.cs
Normal file
23
Netch/Models/GitHub/Asset.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Netch.Models.GitHub
|
||||
{
|
||||
public class Asset
|
||||
{
|
||||
/// <summary>
|
||||
/// name
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("name")]
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// browser_download_url
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("browser_download_url")]
|
||||
public string URL;
|
||||
|
||||
/// <summary>
|
||||
/// size
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("size")]
|
||||
public ulong Size;
|
||||
}
|
||||
}
|
||||
46
Netch/Models/GitHub/Release.cs
Normal file
46
Netch/Models/GitHub/Release.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.GitHub
|
||||
{
|
||||
/// <summary>
|
||||
/// https://api.github.com/repos/{owner}/{repo}/releases
|
||||
/// </summary>
|
||||
public class Release
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("id")]
|
||||
public int ID;
|
||||
|
||||
/// <summary>
|
||||
/// html_url
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("html_url")]
|
||||
public string URL;
|
||||
|
||||
/// <summary>
|
||||
/// tag_name
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("tag_name")]
|
||||
public string VerCode;
|
||||
|
||||
/// <summary>
|
||||
/// draft
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("draft")]
|
||||
public bool Draft;
|
||||
|
||||
/// <summary>
|
||||
/// prerelease
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("prerelease")]
|
||||
public bool Unstable;
|
||||
|
||||
/// <summary>
|
||||
/// assets
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("assets")]
|
||||
public List<Asset> Files;
|
||||
}
|
||||
}
|
||||
19
Netch/Models/Mode/Mode.cs
Normal file
19
Netch/Models/Mode/Mode.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Netch.Models.Mode
|
||||
{
|
||||
public class Mode
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("type")]
|
||||
public ModeType Type;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("remark")]
|
||||
public string Remark;
|
||||
|
||||
public override string ToString() => $"[{((int)this.Type) + 1}] {this.Remark}";
|
||||
}
|
||||
}
|
||||
35
Netch/Models/Mode/ModeType.cs
Normal file
35
Netch/Models/Mode/ModeType.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace Netch.Models.Mode
|
||||
{
|
||||
public enum ModeType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程代理
|
||||
/// </summary>
|
||||
ProcessMode,
|
||||
|
||||
/// <summary>
|
||||
/// 网络共享
|
||||
/// </summary>
|
||||
ShareMode,
|
||||
|
||||
/// <summary>
|
||||
/// 网卡代理
|
||||
/// </summary>
|
||||
TapMode,
|
||||
|
||||
/// <summary>
|
||||
/// 网卡代理
|
||||
/// </summary>
|
||||
TunMode,
|
||||
|
||||
/// <summary>
|
||||
/// 网页代理
|
||||
/// </summary>
|
||||
WebMode,
|
||||
|
||||
/// <summary>
|
||||
/// 代理转发
|
||||
/// </summary>
|
||||
WmpMode
|
||||
}
|
||||
}
|
||||
48
Netch/Models/Mode/ProcessMode/ProcessMode.cs
Normal file
48
Netch/Models/Mode/ProcessMode/ProcessMode.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Mode.ProcessMode
|
||||
{
|
||||
public class ProcessMode : Mode
|
||||
{
|
||||
public ProcessMode()
|
||||
{
|
||||
this.Type = ModeType.ProcessMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 过滤 IPv4 + IPv6 环路流量
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("filterLoopback")]
|
||||
public bool Loopback = false;
|
||||
|
||||
/// <summary>
|
||||
/// 过滤 ICMP 流量(伪造 ICMP 回复)
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("filterICMP")]
|
||||
public bool ICMP = true;
|
||||
|
||||
/// <summary>
|
||||
/// 过滤 TCP 流量
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("filterTCP")]
|
||||
public bool TCP = true;
|
||||
|
||||
/// <summary>
|
||||
/// 过滤 UDP 流量
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("filterUDP")]
|
||||
public bool UDP = true;
|
||||
|
||||
/// <summary>
|
||||
/// 绕过列表
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassList;
|
||||
|
||||
/// <summary>
|
||||
/// 代理列表
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("handle")]
|
||||
public List<string> HandleList;
|
||||
}
|
||||
}
|
||||
18
Netch/Models/Mode/ShareMode/ShareMode.cs
Normal file
18
Netch/Models/Mode/ShareMode/ShareMode.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Mode.ShareMode
|
||||
{
|
||||
public class ShareMode : Mode
|
||||
{
|
||||
public ShareMode()
|
||||
{
|
||||
this.Type = ModeType.ShareMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绕过列表(IP CIDR)
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassList;
|
||||
}
|
||||
}
|
||||
24
Netch/Models/Mode/TapMode/TapMode.cs
Normal file
24
Netch/Models/Mode/TapMode/TapMode.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Mode.TapMode
|
||||
{
|
||||
public class TapMode : Mode
|
||||
{
|
||||
public TapMode()
|
||||
{
|
||||
this.Type = ModeType.TapMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绕过列表(IP CIDR)
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassList;
|
||||
|
||||
/// <summary>
|
||||
/// 代理列表(IP CIDR)
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("handle")]
|
||||
public List<string> HandleList;
|
||||
}
|
||||
}
|
||||
24
Netch/Models/Mode/TunMode/TunMode.cs
Normal file
24
Netch/Models/Mode/TunMode/TunMode.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Mode.TunMode
|
||||
{
|
||||
public class TunMode : Mode
|
||||
{
|
||||
public TunMode()
|
||||
{
|
||||
this.Type = ModeType.TunMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绕过列表(IP CIDR)
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypass")]
|
||||
public List<string> BypassList;
|
||||
|
||||
/// <summary>
|
||||
/// 代理列表(IP CIDR)
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("handle")]
|
||||
public List<string> HandleList;
|
||||
}
|
||||
}
|
||||
30
Netch/Models/Mode/WebMode/WebMode.cs
Normal file
30
Netch/Models/Mode/WebMode/WebMode.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Mode.WebMode
|
||||
{
|
||||
public class WebMode : Mode
|
||||
{
|
||||
public WebMode()
|
||||
{
|
||||
this.Type = ModeType.WebMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置系统代理
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("setSystemProxy")]
|
||||
public bool SetSystemProxy;
|
||||
|
||||
/// <summary>
|
||||
/// 绕过域名后缀
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypassDomainSuffix")]
|
||||
public List<string> BypassDomainSuffix;
|
||||
|
||||
/// <summary>
|
||||
/// 绕过 IP 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("bypassIPs")]
|
||||
public List<string> BypassIPs;
|
||||
}
|
||||
}
|
||||
30
Netch/Models/Mode/WmpMode/WmpMode.cs
Normal file
30
Netch/Models/Mode/WmpMode/WmpMode.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Netch.Models.Mode.WmpMode
|
||||
{
|
||||
public class WmpMode : Mode
|
||||
{
|
||||
public WmpMode()
|
||||
{
|
||||
this.Type = ModeType.WmpMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 监听地址(为空则监听所有 IPv4 + IPv6 地址)
|
||||
/// </summary>
|
||||
public string ListenAddr;
|
||||
|
||||
/// <summary>
|
||||
/// 监听端口
|
||||
/// </summary>
|
||||
public ushort ListenPort;
|
||||
|
||||
/// <summary>
|
||||
/// 远端地址
|
||||
/// </summary>
|
||||
public string RemoteAddr;
|
||||
|
||||
/// <summary>
|
||||
/// 远端端口
|
||||
/// </summary>
|
||||
public ushort RemotePort;
|
||||
}
|
||||
}
|
||||
70
Netch/Models/Server/Server.cs
Normal file
70
Netch/Models/Server/Server.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace Netch.Models.Server
|
||||
{
|
||||
public class Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("type")]
|
||||
public ServerType Type;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("remark")]
|
||||
public string Remark;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("host")]
|
||||
public string Host;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("port")]
|
||||
public ushort Port;
|
||||
|
||||
/// <summary>
|
||||
/// 延迟
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public int Ping = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 测试延迟
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void TestPing() => this.Ping = Utils.Ping.Fetch(this);
|
||||
|
||||
/// <summary>
|
||||
/// 解析地址
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Resolve() => (Utils.DNS.Fetch(this.Host) != IPAddress.Any) ? Utils.DNS.Fetch(this.Host).ToString() : this.Host;
|
||||
|
||||
/// <summary>
|
||||
/// 获取备注
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string name = this.Type switch
|
||||
{
|
||||
ServerType.Socks => "S5",
|
||||
ServerType.Shadowsocks => "SS",
|
||||
ServerType.ShadowsocksR => "SR",
|
||||
ServerType.Trojan => "TR",
|
||||
ServerType.VLess => "VL",
|
||||
ServerType.VMess => "VM",
|
||||
_ => "UN",
|
||||
};
|
||||
|
||||
return String.Format("[{0}] {1}", name, String.IsNullOrEmpty(this.Remark) ? $"{this.Host}:{this.Port}" : this.Remark);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Netch/Models/Server/ServerList.cs
Normal file
19
Netch/Models/Server/ServerList.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Server
|
||||
{
|
||||
public class ServerList
|
||||
{
|
||||
/// <summary>
|
||||
/// 群组
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("name")]
|
||||
public string Group;
|
||||
|
||||
/// <summary>
|
||||
/// 节点
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("list")]
|
||||
public List<Server> List;
|
||||
}
|
||||
}
|
||||
35
Netch/Models/Server/ServerType.cs
Normal file
35
Netch/Models/Server/ServerType.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace Netch.Models.Server
|
||||
{
|
||||
public enum ServerType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Socks5
|
||||
/// </summary>
|
||||
Socks,
|
||||
|
||||
/// <summary>
|
||||
/// Shadowsocks
|
||||
/// </summary>
|
||||
Shadowsocks,
|
||||
|
||||
/// <summary>
|
||||
/// ShadowsocksR
|
||||
/// </summary>
|
||||
ShadowsocksR,
|
||||
|
||||
/// <summary>
|
||||
/// Trojan
|
||||
/// </summary>
|
||||
Trojan,
|
||||
|
||||
/// <summary>
|
||||
/// VLess
|
||||
/// </summary>
|
||||
VLess,
|
||||
|
||||
/// <summary>
|
||||
/// VMess
|
||||
/// </summary>
|
||||
VMess
|
||||
}
|
||||
}
|
||||
30
Netch/Models/Server/Shadowsocks/Global.cs
Normal file
30
Netch/Models/Server/Shadowsocks/Global.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Server.Shadowsocks
|
||||
{
|
||||
public static class Global
|
||||
{
|
||||
public static readonly List<string> Methods = new List<string>()
|
||||
{
|
||||
"bf-cfb",
|
||||
"rc4-md5",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
};
|
||||
}
|
||||
}
|
||||
125
Netch/Models/Server/Shadowsocks/Shadowsocks.cs
Normal file
125
Netch/Models/Server/Shadowsocks/Shadowsocks.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
|
||||
namespace Netch.Models.Server.Shadowsocks
|
||||
{
|
||||
public class Shadowsocks : Server
|
||||
{
|
||||
public Shadowsocks()
|
||||
{
|
||||
this.Type = ServerType.Shadowsocks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("passwd")]
|
||||
public string Passwd;
|
||||
|
||||
/// <summary>
|
||||
/// 加密
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("method")]
|
||||
public string Method;
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("obfs")]
|
||||
public string OBFS;
|
||||
|
||||
/// <summary>
|
||||
/// 插件参数
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("obfsparam")]
|
||||
public string OBFSParam;
|
||||
|
||||
/// <summary>
|
||||
/// 解析链接
|
||||
/// </summary>
|
||||
/// <param name="link">链接</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ParseLink(string link)
|
||||
{
|
||||
if (link.Contains("#"))
|
||||
{
|
||||
this.Remark = HttpUtility.UrlDecode(link.Split('#')[1]);
|
||||
|
||||
link = link.Split('#')[0];
|
||||
}
|
||||
|
||||
if (link.Contains("?"))
|
||||
{
|
||||
var finder = new Regex(@"^(?<data>.+?)\?(.+)$");
|
||||
|
||||
var matches = finder.Match(link);
|
||||
if (matches.Success)
|
||||
{
|
||||
var plugin = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(link).Query).Get("plugin"));
|
||||
if (plugin != null)
|
||||
{
|
||||
var obfs = plugin.Substring(0, plugin.IndexOf(";"));
|
||||
var opts = plugin.Substring(plugin.IndexOf(";") + 1);
|
||||
switch (obfs)
|
||||
{
|
||||
case "obfs-local":
|
||||
case "simple-obfs":
|
||||
case "simple-obfs-tls":
|
||||
obfs = "simple-obfs";
|
||||
break;
|
||||
}
|
||||
|
||||
this.OBFS = obfs;
|
||||
this.OBFSParam = opts;
|
||||
}
|
||||
|
||||
link = matches.Groups["data"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (link.Contains("@"))
|
||||
{
|
||||
var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
|
||||
|
||||
var matches = finder.Match(link);
|
||||
if (!matches.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Host = matches.Groups["server"].Value;
|
||||
|
||||
if (ushort.TryParse(matches.Groups["port"].Value, out var result))
|
||||
{
|
||||
this.Port = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
matches = parser.Match(Utils.Base64.Decode.URLSafe(matches.Groups["base64"].Value));
|
||||
if (!matches.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Passwd = matches.Groups["password"].Value;
|
||||
this.Method = matches.Groups["method"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Method = this.Method.ToLower();
|
||||
return Global.Methods.Contains(this.Method);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Netch/Models/Server/ShadowsocksR/Global.cs
Normal file
47
Netch/Models/Server/ShadowsocksR/Global.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Server.ShadowsocksR
|
||||
{
|
||||
public static class Global
|
||||
{
|
||||
public static readonly List<string> Methods = new List<string>()
|
||||
{
|
||||
"rc4",
|
||||
"bf-cfb",
|
||||
"des-cfb",
|
||||
"rc2-cfb",
|
||||
"rc4-md5",
|
||||
"idea-cfb",
|
||||
"seed-cfb",
|
||||
"cast5-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
};
|
||||
|
||||
public static readonly List<string> Prots = new List<string>()
|
||||
{
|
||||
"origin",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_md5",
|
||||
"auth_aes128_sha1",
|
||||
"auth_chain_a",
|
||||
};
|
||||
|
||||
public static readonly List<string> OBFSs = new List<string>()
|
||||
{
|
||||
"plain",
|
||||
"http_post",
|
||||
"http_simple",
|
||||
"tls1.2_ticket_auth"
|
||||
};
|
||||
}
|
||||
}
|
||||
140
Netch/Models/Server/ShadowsocksR/ShadowsocksR.cs
Normal file
140
Netch/Models/Server/ShadowsocksR/ShadowsocksR.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Netch.Models.Server.ShadowsocksR
|
||||
{
|
||||
public class ShadowsocksR : Server
|
||||
{
|
||||
public ShadowsocksR()
|
||||
{
|
||||
this.Type = ServerType.ShadowsocksR;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("passwd")]
|
||||
public string Passwd;
|
||||
|
||||
/// <summary>
|
||||
/// 加密
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("method")]
|
||||
public string Method;
|
||||
|
||||
/// <summary>
|
||||
/// 协议
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("prot")]
|
||||
public string Prot;
|
||||
|
||||
/// <summary>
|
||||
/// 协议参数
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("protparam")]
|
||||
public string ProtParam;
|
||||
|
||||
/// <summary>
|
||||
/// 混淆
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("obfs")]
|
||||
public string OBFS;
|
||||
|
||||
/// <summary>
|
||||
/// 混淆参数
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("obfsparam")]
|
||||
public string OBFSParam;
|
||||
|
||||
/// <summary>
|
||||
/// 解析链接
|
||||
/// </summary>
|
||||
/// <param name="link">链接</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ParseLink(string link)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ssr = new Regex(@"ssr://([A-Za-z0-9+/=_-]+)", RegexOptions.IgnoreCase).Match(link);
|
||||
if (!ssr.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = Utils.Base64.Decode.URLSafe(ssr.Groups[1].Value);
|
||||
var dict = new Dictionary<string, string>();
|
||||
|
||||
var offset = data.IndexOf(@"?", StringComparison.Ordinal);
|
||||
if (offset > 0)
|
||||
{
|
||||
dict = ParseParam(data.Substring(offset + 1));
|
||||
data = data.Substring(0, offset);
|
||||
}
|
||||
|
||||
if (data.IndexOf("/", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
var matches = new Regex(@"^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)").Match(data);
|
||||
if (!matches.Success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("remarks"))
|
||||
{
|
||||
this.Remark = Utils.Base64.Decode.URLSafe(dict["remarks"]);
|
||||
}
|
||||
|
||||
this.Host = matches.Groups[1].Value;
|
||||
if (!ushort.TryParse(matches.Groups[2].Value, out this.Port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
this.Passwd = Utils.Base64.Decode.URLSafe(matches.Groups[6].Value);
|
||||
this.Method = matches.Groups[4].Value.ToLower();
|
||||
|
||||
this.Prot = (matches.Groups[3].Value.Length == 0 ? "origin" : matches.Groups[3].Value).Replace("_compatible", String.Empty).ToLower();
|
||||
if (dict.ContainsKey("protoparam"))
|
||||
{
|
||||
this.ProtParam = Utils.Base64.Decode.URLSafe(dict["protoparam"]);
|
||||
}
|
||||
|
||||
this.OBFS = (matches.Groups[5].Value.Length == 0 ? @"plain" : matches.Groups[5].Value).Replace("_compatible", String.Empty).ToLower();
|
||||
if (dict.ContainsKey("obfsparam"))
|
||||
{
|
||||
this.OBFSParam = Utils.Base64.Decode.URLSafe(dict["obfsparam"]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
global::Netch.Global.Logger.Warning(e.ToString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> ParseParam(string str)
|
||||
{
|
||||
var dict = new Dictionary<string, string>();
|
||||
var obfs = str.Split('&');
|
||||
for (int i = 0; i < str.Length; i++)
|
||||
{
|
||||
if (obfs[i].IndexOf('=') > 0)
|
||||
{
|
||||
var index = obfs[i].IndexOf('=');
|
||||
|
||||
var k = obfs[i].Substring(0, index);
|
||||
var v = obfs[i].Substring(index + 1);
|
||||
dict[k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Netch/Models/Server/Socks/Socks.cs
Normal file
70
Netch/Models/Server/Socks/Socks.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Models.Server.Socks
|
||||
{
|
||||
public class Socks : Server
|
||||
{
|
||||
public Socks()
|
||||
{
|
||||
this.Type = ServerType.Socks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("username")]
|
||||
public string Username;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonProperty("password")]
|
||||
public string Password;
|
||||
|
||||
/// <summary>
|
||||
/// 解析链接
|
||||
/// </summary>
|
||||
/// <param name="link">链接</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ParseLink(string link)
|
||||
{
|
||||
var list = link
|
||||
.Replace("tg://socks?", "")
|
||||
.Replace("https://t.me/socks?", "")
|
||||
.Split('&');
|
||||
|
||||
var dict = new Dictionary<string, string>();
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
var s = list[i].Split('=');
|
||||
if (s.Length != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dict[s[0]] = s[1];
|
||||
}
|
||||
|
||||
if (!dict.ContainsKey("server") || !dict.ContainsKey("port") || !ushort.TryParse(dict["port"], out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Host = dict["server"];
|
||||
this.Port = ushort.Parse(dict["port"]);
|
||||
|
||||
if (dict.ContainsKey("user") && !String.IsNullOrEmpty(dict["user"]))
|
||||
{
|
||||
this.Username = dict["user"];
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("pass") && !String.IsNullOrEmpty(dict["pass"]))
|
||||
{
|
||||
this.Username = dict["pass"];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Netch/Models/Server/Trojan/Trojan.cs
Normal file
45
Netch/Models/Server/Trojan/Trojan.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace Netch.Models.Server.Trojan
|
||||
{
|
||||
public class Trojan : Server
|
||||
{
|
||||
public Trojan()
|
||||
{
|
||||
this.Type = ServerType.Trojan;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Passwd;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装 SNI 标头
|
||||
/// </summary>
|
||||
public string SNI;
|
||||
|
||||
/// <summary>
|
||||
/// 复用会话
|
||||
/// </summary>
|
||||
public bool Reuse = true;
|
||||
|
||||
/// <summary>
|
||||
/// Session Ticket
|
||||
/// </summary>
|
||||
public bool Ticket = false;
|
||||
|
||||
/// <summary>
|
||||
/// 不安全模式(跳过证书验证、跳过主机名验证)
|
||||
/// </summary>
|
||||
public bool Insecure = true;
|
||||
|
||||
/// <summary>
|
||||
/// 解析链接
|
||||
/// </summary>
|
||||
/// <param name="link">链接</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ParseLink(string link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Netch/Models/Server/VLess/VLess.cs
Normal file
30
Netch/Models/Server/VLess/VLess.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Netch.Models.Server.VLess
|
||||
{
|
||||
public class VLess : Server
|
||||
{
|
||||
public VLess()
|
||||
{
|
||||
this.Type = ServerType.VLess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义配置
|
||||
/// </summary>
|
||||
public bool Custom = true;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义配置文件路径
|
||||
/// </summary>
|
||||
public string FilePath;
|
||||
|
||||
/// <summary>
|
||||
/// 解析链接
|
||||
/// </summary>
|
||||
/// <param name="link">链接</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ParseLink(string link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Netch/Models/Server/VMess/VMess.cs
Normal file
30
Netch/Models/Server/VMess/VMess.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Netch.Models.Server.VMess
|
||||
{
|
||||
public class VMess : Server
|
||||
{
|
||||
public VMess()
|
||||
{
|
||||
this.Type = ServerType.VMess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义配置
|
||||
/// </summary>
|
||||
public bool Custom = true;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义配置文件路径
|
||||
/// </summary>
|
||||
public string FilePath;
|
||||
|
||||
/// <summary>
|
||||
/// 解析链接
|
||||
/// </summary>
|
||||
/// <param name="link">链接</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ParseLink(string link)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Netch/NativeMethods.cs
Normal file
13
Netch/NativeMethods.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch
|
||||
{
|
||||
public static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32")]
|
||||
public static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern bool AttachConsole(uint dwProcessId);
|
||||
}
|
||||
}
|
||||
16
Netch/Netch.csproj
Normal file
16
Netch/Netch.csproj
Normal file
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.Management" Version="5.0.0" />
|
||||
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
163
Netch/Tools/Guard.cs
Normal file
163
Netch/Tools/Guard.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Netch.Tools
|
||||
{
|
||||
public class Guard
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动信息
|
||||
/// </summary>
|
||||
public ProcessStartInfo StartInfo;
|
||||
|
||||
/// <summary>
|
||||
/// 标准模式
|
||||
/// </summary>
|
||||
public bool Standard = true;
|
||||
|
||||
/// <summary>
|
||||
/// 判定启动的字符串
|
||||
/// </summary>
|
||||
public List<string> JudgmentStarted;
|
||||
|
||||
/// <summary>
|
||||
/// 判定停止的字符串
|
||||
/// </summary>
|
||||
public List<string> JudgmentStopped;
|
||||
|
||||
/// <summary>
|
||||
/// 自动重启
|
||||
/// </summary>
|
||||
public bool AutoRestart;
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Create()
|
||||
{
|
||||
this.instance = new Process
|
||||
{
|
||||
StartInfo = this.StartInfo,
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
this.instance.StartInfo.RedirectStandardError = true;
|
||||
this.instance.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
this.instance.Exited += this.OnExited;
|
||||
this.instance.ErrorDataReceived += this.OnOutputDataReceived;
|
||||
this.instance.OutputDataReceived += this.OnOutputDataReceived;
|
||||
|
||||
this.Started = false;
|
||||
this.Starting = true;
|
||||
this.instance.Start();
|
||||
|
||||
if (!this.Standard)
|
||||
{
|
||||
this.Started = true;
|
||||
this.instance.BeginErrorReadLine();
|
||||
this.instance.BeginOutputReadLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
this.instance.BeginErrorReadLine();
|
||||
this.instance.BeginOutputReadLine();
|
||||
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (this.Started)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.Starting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.Delete();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Delete()
|
||||
{
|
||||
this.AutoRestart = false;
|
||||
|
||||
try
|
||||
{
|
||||
this.instance?.Kill();
|
||||
this.instance?.WaitForExit();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 进程
|
||||
/// </summary>
|
||||
private Process instance;
|
||||
|
||||
/// <summary>
|
||||
/// 是否已启动
|
||||
/// </summary>
|
||||
private bool Started = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否正在启动中
|
||||
/// </summary>
|
||||
private bool Starting = false;
|
||||
|
||||
private void OnExited(object sender, EventArgs e)
|
||||
{
|
||||
if (this.Started && this.AutoRestart)
|
||||
{
|
||||
Thread.Sleep(200);
|
||||
|
||||
this.Create();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (this.Starting)
|
||||
{
|
||||
if (this.instance.HasExited)
|
||||
{
|
||||
this.Starting = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.JudgmentStarted.Count; i++)
|
||||
{
|
||||
if (e.Data.ToLower().Contains(this.JudgmentStarted[i]))
|
||||
{
|
||||
this.Started = true;
|
||||
this.Starting = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.JudgmentStopped.Count; i++)
|
||||
{
|
||||
if (e.Data.ToLower().Contains(this.JudgmentStopped[i]))
|
||||
{
|
||||
this.Starting = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"[Netch][Tools.Guard] {e.Data}");
|
||||
}
|
||||
}
|
||||
}
|
||||
84
Netch/Tools/Logger.cs
Normal file
84
Netch/Tools/Logger.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Netch.Tools
|
||||
{
|
||||
public class Logger
|
||||
{
|
||||
/// <summary>
|
||||
/// 互斥锁
|
||||
/// </summary>
|
||||
private object mutex = new();
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="text"></param>
|
||||
private void WriteLine(string name, string text)
|
||||
{
|
||||
var method = new StackTrace().GetFrame(2).GetMethod();
|
||||
var content = $"[{DateTime.Now}][{method.ReflectedType.Name}.{method.Name}][{name}] {text}";
|
||||
|
||||
lock (mutex)
|
||||
{
|
||||
File.AppendAllText(this.SavePath, $"{content}\n");
|
||||
}
|
||||
|
||||
Console.WriteLine($"[Netch]{content}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存路径
|
||||
/// </summary>
|
||||
public string SavePath;
|
||||
|
||||
/// <summary>
|
||||
/// 调试
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void Debug(string text)
|
||||
{
|
||||
this.WriteLine("DEBUG", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void Info(string text)
|
||||
{
|
||||
this.WriteLine("INFO", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 警告
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void Warning(string text)
|
||||
{
|
||||
this.WriteLine("WARNING", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void Error(string text)
|
||||
{
|
||||
this.WriteLine("ERROR", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 崩溃
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void Fatal(string text)
|
||||
{
|
||||
this.WriteLine("FATAL", text);
|
||||
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
Netch/Tools/TunTap/Outbound.cs
Normal file
71
Netch/Tools/TunTap/Outbound.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Netch.Tools.TunTap
|
||||
{
|
||||
public class Outbound
|
||||
{
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public uint Index;
|
||||
|
||||
/// <summary>
|
||||
/// 适配器
|
||||
/// </summary>
|
||||
public NetworkInterface Interface;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public IPAddress Address;
|
||||
|
||||
/// <summary>
|
||||
/// 掩码
|
||||
/// </summary>
|
||||
public IPAddress Netmask;
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public IPAddress Gateway;
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Get()
|
||||
{
|
||||
if (Vanara.PInvoke.Win32Error.NO_ERROR != Vanara.PInvoke.IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var route))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Index = route.dwForwardIfIndex;
|
||||
this.Interface = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.First(nic =>
|
||||
{
|
||||
var ipp = nic.GetIPProperties();
|
||||
if (nic.Supports(NetworkInterfaceComponent.IPv4))
|
||||
{
|
||||
return ipp.GetIPv4Properties().Index == this.Index;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
var addr = this.Interface.GetIPProperties().UnicastAddresses.First(ipf =>
|
||||
{
|
||||
return ipf.Address.AddressFamily == AddressFamily.InterNetwork;
|
||||
});
|
||||
|
||||
this.Address = addr.Address;
|
||||
this.Netmask = addr.IPv4Mask;
|
||||
this.Gateway = new IPAddress(route.dwForwardNextHop.S_un_b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Netch/Utils/Base64.cs
Normal file
34
Netch/Utils/Base64.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Base64
|
||||
{
|
||||
public static class Encode
|
||||
{
|
||||
public static string Normal(string text)
|
||||
{
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text));
|
||||
}
|
||||
|
||||
public static string URLSafe(string text)
|
||||
{
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)).Replace("+", "-").Replace("/", "_").Replace("=", "");
|
||||
}
|
||||
}
|
||||
|
||||
public static class Decode
|
||||
{
|
||||
public static string Normal(string text)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(text.PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
|
||||
}
|
||||
|
||||
public static string URLSafe(string text)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(text.Replace("-", "+").Replace("_", "/").PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
Netch/Utils/Config.cs
Normal file
6
Netch/Utils/Config.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Config
|
||||
{
|
||||
}
|
||||
}
|
||||
50
Netch/Utils/DNS.cs
Normal file
50
Netch/Utils/DNS.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Net;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class DNS
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存表
|
||||
/// </summary>
|
||||
private static readonly Hashtable Cache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// 获取 IP 地址
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static IPAddress Fetch(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Cache.Contains(name))
|
||||
{
|
||||
return Cache[name] as IPAddress;
|
||||
}
|
||||
|
||||
var task = Dns.GetHostAddressesAsync(name);
|
||||
if (!task.Wait(1000))
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
|
||||
if (task.Result.Length == 0)
|
||||
{
|
||||
return IPAddress.Any;
|
||||
}
|
||||
|
||||
Cache.Add(name, task.Result[0]);
|
||||
return task.Result[0];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Warning(e.ToString());
|
||||
|
||||
return IPAddress.Any;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Netch/Utils/FileHelper.cs
Normal file
33
Netch/Utils/FileHelper.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class FileHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 计算文件 SHA256 校验和
|
||||
/// </summary>
|
||||
/// <param name="name">文件路径</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] Checksum(string name)
|
||||
{
|
||||
using (var algo = SHA256.Create())
|
||||
{
|
||||
using (var fs = File.OpenRead(name))
|
||||
{
|
||||
return algo.ComputeHash(fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个文件是否完全相同
|
||||
/// </summary>
|
||||
/// <param name="oPath">文件路径</param>
|
||||
/// <param name="nPath">文件路径</param>
|
||||
/// <returns></returns>
|
||||
public static bool Equals(string oPath, string nPath) => Checksum(oPath).SequenceEqual(Checksum(nPath));
|
||||
}
|
||||
}
|
||||
73
Netch/Utils/GitHub.cs
Normal file
73
Netch/Utils/GitHub.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class GitHub
|
||||
{
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public static readonly string URL = "https://api.github.com/repos/NetchX/Netch/releases";
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否有更新
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int HasUpdate()
|
||||
{
|
||||
var list = GetReleaseList();
|
||||
if (list.Count < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i].Draft)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Global.Config.Generic.Unstable)
|
||||
{
|
||||
if (list[i].Unstable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (list[i].VerCode.Equals(Global.VerCode))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return list[i].ID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取单个发布
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static Models.GitHub.Release GetRelease(int id)
|
||||
{
|
||||
var data = HTTP.GetString($"{URL}/{id}");
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<Models.GitHub.Release>(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取发布列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<Models.GitHub.Release> GetReleaseList()
|
||||
{
|
||||
var data = HTTP.GetString(URL);
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<Models.GitHub.Release>>(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Netch/Utils/HTTP.cs
Normal file
72
Netch/Utils/HTTP.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class HTTP
|
||||
{
|
||||
/// <summary>
|
||||
/// User Agent
|
||||
/// </summary>
|
||||
public static readonly string DefaultUA = $"Netch/{Global.VerCode}";
|
||||
|
||||
/// <summary>
|
||||
/// 创建请求
|
||||
/// </summary>
|
||||
/// <param name="url">地址</param>
|
||||
/// <param name="timeout">超时</param>
|
||||
/// <returns></returns>
|
||||
public static HttpWebRequest CreateRequest(string url, int timeout = 0)
|
||||
{
|
||||
var request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.UserAgent = DefaultUA;
|
||||
request.Accept = "*/*";
|
||||
request.KeepAlive = true;
|
||||
request.Timeout = timeout;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public static string GetString(string url)
|
||||
{
|
||||
var request = CreateRequest(url, 10000);
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
|
||||
using (var rs = response.GetResponseStream())
|
||||
{
|
||||
using (var sr = new StreamReader(rs, Encoding.UTF8))
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetString(string url, int timeout)
|
||||
{
|
||||
var request = CreateRequest(url, timeout);
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
|
||||
using (var rs = response.GetResponseStream())
|
||||
{
|
||||
using (var sr = new StreamReader(rs, Encoding.UTF8))
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetString(HttpWebRequest request)
|
||||
{
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
|
||||
using (var rs = response.GetResponseStream())
|
||||
{
|
||||
using (var sr = new StreamReader(rs, Encoding.UTF8))
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Netch/Utils/Netfilter.cs
Normal file
109
Netch/Utils/Netfilter.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Netfilter
|
||||
{
|
||||
public static class Methods
|
||||
{
|
||||
public enum NF_STATUS : int
|
||||
{
|
||||
NF_STATUS_SUCCESS = 0,
|
||||
NF_STATUS_FAIL = -1,
|
||||
NF_STATUS_INVALID_ENDPOINT_ID = -2,
|
||||
NF_STATUS_NOT_INITIALIZED = -3,
|
||||
NF_STATUS_IO_ERROR = -4
|
||||
}
|
||||
|
||||
[DllImport("nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_registerDriver(string name);
|
||||
|
||||
[DllImport("nfapinet", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern NF_STATUS nf_unRegisterDriver(string driverName);
|
||||
}
|
||||
|
||||
public static readonly string dName = "netfilter2";
|
||||
public static readonly string oPath = Path.Combine(Environment.SystemDirectory, "drivers\\netfilter2.sys");
|
||||
public static readonly string nPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin\\netfilter2.sys");
|
||||
|
||||
/// <summary>
|
||||
/// 注册 Netfilter 驱动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Create()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Delete())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
File.Copy(nPath, oPath);
|
||||
var status = Methods.nf_registerDriver(dName);
|
||||
if (status != Methods.NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Global.Logger.Error($"注册 Netfilter 驱动失败:{status}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error(e.ToString());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新 Netfilter 驱动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Update()
|
||||
{
|
||||
if (!File.Exists(oPath))
|
||||
{
|
||||
return Create();
|
||||
}
|
||||
|
||||
if (!FileHelper.Equals(oPath, nPath))
|
||||
{
|
||||
return Create();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除 Netfilter 驱动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Delete()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(oPath))
|
||||
{
|
||||
var status = Methods.nf_unRegisterDriver(dName);
|
||||
if (status != Methods.NF_STATUS.NF_STATUS_SUCCESS)
|
||||
{
|
||||
Global.Logger.Error($"取消注册 Netfilter 驱动失败:{status}");
|
||||
return false;
|
||||
}
|
||||
|
||||
File.Delete(oPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error($"删除 Netfilter 驱动失败:{e}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Netch/Utils/Ping.cs
Normal file
130
Netch/Utils/Ping.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class Ping
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存内容
|
||||
/// </summary>
|
||||
private class CacheEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存时间
|
||||
/// </summary>
|
||||
public long Unix;
|
||||
|
||||
/// <summary>
|
||||
/// 延迟
|
||||
/// </summary>
|
||||
public int Time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存表
|
||||
/// </summary>
|
||||
private static Hashtable Cache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ICMP 延迟
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
private static int ICMPing(IPAddress addr)
|
||||
{
|
||||
using (var client = new System.Net.NetworkInformation.Ping())
|
||||
{
|
||||
var tk = client.SendPingAsync(addr);
|
||||
if (!tk.Wait(1000))
|
||||
{
|
||||
return 999;
|
||||
}
|
||||
|
||||
return Convert.ToInt32(tk.Result.RoundtripTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 TCP 延迟
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
private static int TCPPing(IPAddress addr, ushort port)
|
||||
{
|
||||
using (var client = new TcpClient())
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var tk = client.ConnectAsync(addr, port);
|
||||
|
||||
if (!tk.Wait(1000))
|
||||
{
|
||||
sw.Stop();
|
||||
return 999;
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return Convert.ToInt32(sw.Elapsed.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取延迟
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
public static int Fetch(Models.Server.Server s)
|
||||
{
|
||||
/*
|
||||
* -1 : Not Test
|
||||
* -2 : DNS Exception
|
||||
* -3 : Exception
|
||||
* 999 : Timeout
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
var addr = DNS.Fetch(s.Host);
|
||||
if (addr == IPAddress.Any)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (Cache.Contains(addr))
|
||||
{
|
||||
var rule = Cache[addr] as CacheEntry;
|
||||
if (DateTimeOffset.Now.ToUnixTimeSeconds() - rule.Unix < 30)
|
||||
{
|
||||
return rule.Time;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cache.Remove(addr);
|
||||
}
|
||||
}
|
||||
|
||||
var time = 0;
|
||||
if (Global.Config.Generic.ICMPing)
|
||||
{
|
||||
time = ICMPing(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TCPPing(addr, s.Port);
|
||||
}
|
||||
|
||||
Cache.Add(addr, new CacheEntry() { Unix = DateTimeOffset.Now.ToUnixTimeSeconds(), Time = time });
|
||||
return time;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Warning(e.ToString());
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Netch/Utils/RouteHelper.cs
Normal file
132
Netch/Utils/RouteHelper.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class RouteHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 将 Luid 转换为 Index 索引
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern ulong ConvertLuidToIndex(ulong id);
|
||||
|
||||
/// <summary>
|
||||
/// 绑定 IP 地址(Windows XP)
|
||||
/// </summary>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="netmask"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateIPv4(string address, string netmask, ulong index);
|
||||
|
||||
/// <summary>
|
||||
/// 绑定 IP 地址
|
||||
/// </summary>
|
||||
/// <param name="inet"></param>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="cidr"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
|
||||
|
||||
/// <summary>
|
||||
/// 创建路由
|
||||
/// </summary>
|
||||
/// <param name="inet"></param>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="cidr"></param>
|
||||
/// <param name="gateway"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool CreateRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index);
|
||||
|
||||
/// <summary>
|
||||
/// 删除路由
|
||||
/// </summary>
|
||||
/// <param name="inet"></param>
|
||||
/// <param name="address"></param>
|
||||
/// <param name="cidr"></param>
|
||||
/// <param name="gateway"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool DeleteRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index);
|
||||
|
||||
/// <summary>
|
||||
/// 使用索引获取适配器
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public static NetworkInterface GetInterfaceByIndex(ulong index)
|
||||
{
|
||||
NetworkInterface adapter = null;
|
||||
|
||||
var list = NetworkInterface.GetAllNetworkInterfaces();
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
if (list[i].Supports(NetworkInterfaceComponent.IPv4))
|
||||
{
|
||||
if (list[i].GetIPProperties().GetIPv4Properties().Index == Convert.ToInt32(index))
|
||||
{
|
||||
adapter = list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (list[i].Supports(NetworkInterfaceComponent.IPv6))
|
||||
{
|
||||
if (list[i].GetIPProperties().GetIPv6Properties().Index == Convert.ToInt32(index))
|
||||
{
|
||||
adapter = list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用名称获取适配器索引
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static ulong GetInterfaceIndexByDescription(string name)
|
||||
{
|
||||
var ada = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.First(nic =>
|
||||
{
|
||||
if (nic.Description.Equals(name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
int index = 0;
|
||||
if (ada.Supports(NetworkInterfaceComponent.IPv4))
|
||||
{
|
||||
index = ada.GetIPProperties().GetIPv4Properties().Index;
|
||||
}
|
||||
else if (ada.Supports(NetworkInterfaceComponent.IPv6))
|
||||
{
|
||||
index = ada.GetIPProperties().GetIPv6Properties().Index;
|
||||
}
|
||||
|
||||
return Convert.ToUInt64(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Netch/Utils/WinTUN.cs
Normal file
78
Netch/Utils/WinTUN.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Netch.Utils
|
||||
{
|
||||
public static class WinTUN
|
||||
{
|
||||
public static string oPath = Path.Combine(Environment.SystemDirectory, "wintun.dll");
|
||||
public static string nPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin\\wintun.bin");
|
||||
|
||||
/// <summary>
|
||||
/// 注册 WinTUN 驱动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Create()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Delete())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
File.Copy(nPath, oPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error($"注册 WinTUN 驱动失败:{e}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新 WinTUN 驱动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Update()
|
||||
{
|
||||
if (!File.Exists(oPath))
|
||||
{
|
||||
return Create();
|
||||
}
|
||||
|
||||
if (!FileHelper.Equals(oPath, nPath))
|
||||
{
|
||||
return Create();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除 WinTUN 驱动
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool Delete()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(oPath))
|
||||
{
|
||||
File.Delete(oPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Global.Logger.Error($"删除 WinTUN 驱动失败:{e}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user