mirror of
https://github.com/netchx/netch.git
synced 2026-03-18 18:13:21 +08:00
Add files via upload
This commit is contained in:
26
.github/workflows/build.yml
vendored
Normal file
26
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Netch Build CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
run: |
|
||||
.\build.ps1 -Configuration Release -OutputPath release
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Netch
|
||||
path: release
|
||||
49
.github/workflows/release.yml
vendored
Normal file
49
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Netch Release CI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: MSBuild
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
run: |
|
||||
.\build.ps1 -Configuration Release -OutputPath release
|
||||
|
||||
- name: Package
|
||||
shell: pwsh
|
||||
run: |
|
||||
7z a -mx9 Netch.7z release
|
||||
7z rn Netch.7z release Netch
|
||||
echo "NETCH_SHA256=$(.\sha256.ps1 Netch.7z)" | Out-File -Append -Encoding UTF8 -FilePath $Env:GITHUB_ENV
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
prerelease: ${{ contains(github.ref, '-') }}
|
||||
draft: false
|
||||
files: |
|
||||
Netch.7z
|
||||
body: |
|
||||
[](https://t.me/netch_channel) [](https://t.me/netch_group)
|
||||
## 更新日志
|
||||
* 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新
|
||||
|
||||
## 校验和
|
||||
| 文件名 | SHA256 |
|
||||
| :- | :- |
|
||||
| Netch.7z | ${{ env.Netch_SHA256 }} |
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/.vs
|
||||
/.idea
|
||||
/packages
|
||||
/TestResults
|
||||
30
Netch.sln
Normal file
30
Netch.sln
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31205.134
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Netch", "Netch\Netch.csproj", "{A193DF89-ADCF-4DB4-B75C-729C8BA8A9F3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{09222C6B-2FFB-4DA7-BC75-CB0A80086711}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A193DF89-ADCF-4DB4-B75C-729C8BA8A9F3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A193DF89-ADCF-4DB4-B75C-729C8BA8A9F3}.Debug|x64.Build.0 = Debug|x64
|
||||
{A193DF89-ADCF-4DB4-B75C-729C8BA8A9F3}.Release|x64.ActiveCfg = Release|x64
|
||||
{A193DF89-ADCF-4DB4-B75C-729C8BA8A9F3}.Release|x64.Build.0 = Release|x64
|
||||
{09222C6B-2FFB-4DA7-BC75-CB0A80086711}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{09222C6B-2FFB-4DA7-BC75-CB0A80086711}.Debug|x64.Build.0 = Debug|x64
|
||||
{09222C6B-2FFB-4DA7-BC75-CB0A80086711}.Release|x64.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1E271FD7-9623-47D5-B3AF-309BC23CB48E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
README.md
Normal file
55
README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
<p align="center"><img src="https://github.com/NetchX/Netch/blob/master/Netch/Resources/Netch.png?raw=true" width="128" /></p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
# Netch
|
||||
A simple proxy client
|
||||
|
||||
[](https://t.me/netch_group)
|
||||
[](https://t.me/netch_channel)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
[](https://github.com/NetchX/Netch/releases)
|
||||
</div>
|
||||
|
||||
## Features
|
||||
Some features may not be implemented in version 1
|
||||
|
||||
### Modes
|
||||
- ProcessMode - Use Netfilter driver to intercept process traffic
|
||||
- ShareMode - Share your network based on WinPcap / Npcap
|
||||
- TapMode - Use TAP-Windows driver to create virtual adapter
|
||||
- TunMode - Use WinTUN driver to create virtual adapter
|
||||
- WebMode - Web proxy mode
|
||||
- WmpMode - Proxy forwarding (eg. OBS Streaming)
|
||||
|
||||
### Protocols
|
||||
- [Socks5](https://www.wikiwand.com/en/SOCKS)
|
||||
- [Shadowsocks](https://github.com/shadowsocks/shadowsocks-libev)
|
||||
- [ShadowsocksR](https://github.com/shadowsocksrr/shadowsocksr-libev)
|
||||
- [Trojan](https://trojan-gfw.github.io/trojan/)
|
||||
- [VLess](https://github.com/xtls/xray-core)
|
||||
- [VMess](https://github.com/v2fly/v2ray-core)
|
||||
|
||||
### Others
|
||||
- UDP NAT FullCone (May limited by your server)
|
||||
- .NET 5.0 x64
|
||||
|
||||
## Sponsor
|
||||
<a href="https://www.jetbrains.com/?from=Netch"><img src="jetbrains.svg" alt="JetBrains" width="200"/></a>
|
||||
|
||||
- [NeroCloud](https://nerocloud.io)
|
||||
|
||||
## Donate
|
||||
- XMR *48ju3ELNZEa6wwPBMexCJ9G218BGY2XwhH6B6bmkFuJ3QgM4hPw2Pra35jPtuBZSc7SLNWeBpiWJZWjQeMAiLnTx2tH2Efx*
|
||||
- ETH *0x23dac0a93bcd71fec7a95833ad030338f167f185*
|
||||
|
||||
## Credit
|
||||
- [TAP-Windows](https://github.com/OpenVPN/tap-windows6)
|
||||
- [WinTUN](https://www.wintun.net)
|
||||
- [NetFilter](https://netfiltersdk.com)
|
||||
- [aioCloud](https://github.com/aiocloud)
|
||||
- [Shadowsocks](https://github.com/shadowsocks/shadowsocks-libev)
|
||||
- [ShadowsocksR](https://github.com/shadowsocksrr/shadowsocksr-libev)
|
||||
- [Trojan](https://github.com/trojan-gfw/trojan)
|
||||
- [V2Ray](https://github.com/v2fly/v2ray-core)
|
||||
- [XRay](https://github.com/xtls/xray-core)
|
||||
3
Tests/.gitignore
vendored
Normal file
3
Tests/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/bin
|
||||
/obj
|
||||
/*.csproj.user
|
||||
15
Tests/Global.cs
Normal file
15
Tests/Global.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Global
|
||||
{
|
||||
[TestMethod]
|
||||
public void Test()
|
||||
{
|
||||
Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Tests/Tests.csproj
Normal file
18
Tests/Tests.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
40
build.ps1
Normal file
40
build.ps1
Normal file
@@ -0,0 +1,40 @@
|
||||
param (
|
||||
[Parameter()]
|
||||
[ValidateSet('Debug', 'Release')]
|
||||
[string]
|
||||
$Configuration = 'Release',
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$OutputPath = 'release',
|
||||
|
||||
[Parameter()]
|
||||
[bool]
|
||||
$SelfContained = $False,
|
||||
|
||||
[Parameter()]
|
||||
[bool]
|
||||
$PublishReadyToRun = $False,
|
||||
|
||||
[Parameter()]
|
||||
[bool]
|
||||
$PublishSingleFile = $True
|
||||
)
|
||||
|
||||
.\scripts\download.ps1 $OutputPath
|
||||
if ( -Not $? ) { exit 1 }
|
||||
|
||||
Write-Host "Building $Configuration to $OutputPath"
|
||||
dotnet publish `
|
||||
-c $Configuration `
|
||||
-r "win-x64" `
|
||||
-p:Platform="x64" `
|
||||
-p:PublishSingleFile=$PublishSingleFile `
|
||||
-p:SelfContained=$SelfContained `
|
||||
-p:PublishTrimmed=$SelfContained `
|
||||
-p:PublishReadyToRun=$PublishReadyToRun `
|
||||
-o $OutputPath `
|
||||
Netch\Netch.csproj
|
||||
|
||||
exit $lastExitCode
|
||||
15
clean.ps1
Normal file
15
clean.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
function Delete {
|
||||
param([string]$Path)
|
||||
|
||||
if (Test-Path $Path) {
|
||||
Remove-Item -Recurse -Force $Path | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
Delete ".vs"
|
||||
Delete "Netch\bin"
|
||||
Delete "Netch\obj"
|
||||
Delete "Tests\bin"
|
||||
Delete "Tests\obj"
|
||||
Delete "TestResults"
|
||||
exit 0
|
||||
43
jetbrains.svg
Normal file
43
jetbrains.svg
Normal file
@@ -0,0 +1,43 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="263" height="147" viewBox="0 0 263 147">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="54.4568" y1="122.5936" x2="251.779" y2="10.2057" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#00adee"/>
|
||||
<stop offset="1" stop-color="#9f76a6"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="80.247" y1="38.7607" x2="241.2622" y2="10.9511" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ec037c"/>
|
||||
<stop offset="1" stop-color="#9f76a6"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="75.7205" y1="33.5582" x2="127.8253" y2="123.9392" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ec037c"/>
|
||||
<stop offset="1" stop-color="#5c2d90"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-4" x1="7.4647" y1="44.578" x2="129.4543" y2="125.0813" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#44c7f4"/>
|
||||
<stop offset="1" stop-color="#5c2d90"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g>
|
||||
<path d="M261.1839,10.3622a9.6784,9.6784,0,0,0-14.7448-8.2463l0-.0006L20.6942,136.0746h0a4.6974,4.6974,0,1,0,4.1326,8.4348h0q0.09-.0467.1784-0.097l230.5273-125.25a9.653,9.653,0,0,0,1.1508-.6253l0.0332-.018-0.0014-.0023A9.6682,9.6682,0,0,0,261.1839,10.3622Z" fill="url(#linear-gradient)"/>
|
||||
<path d="M261.1839,10.3622A9.6782,9.6782,0,0,0,251.5057.684q-0.2747,0-.5456.0157-0.25.0143-.4975,0.041L76.7981,25.4187A13.7347,13.7347,0,1,0,83.5355,51.983L252.8044,19.9512a9.6363,9.6363,0,0,0,1.0358-.196l0.02-.0039,0-.0008A9.6811,9.6811,0,0,0,261.1839,10.3622Z" fill="url(#linear-gradient-2)"/>
|
||||
<path d="M145.2028,123.63a17.2372,17.2372,0,0,0-3.0637-9.4254L91.3045,32.3521A13.7366,13.7366,0,0,0,66.1132,42.9507h0a13.6332,13.6332,0,0,0,1.043,2.4984s45.2334,86.37,45.5824,86.9979q0.3089,0.556.6567,1.0861h0A17.32,17.32,0,0,0,145.2028,123.63Z" fill="url(#linear-gradient-3)"/>
|
||||
<path d="M145.2028,123.63a17.2979,17.2979,0,0,0-7.63-13.9419h0a17.3061,17.3061,0,0,0-2.6994-1.4911L9.5484,38.9679a6.064,6.064,0,0,0-6.5074,10.187l114.3963,88.704A17.3191,17.3191,0,0,0,145.2028,123.63Z" fill="url(#linear-gradient-4)"/>
|
||||
<g>
|
||||
<rect x="69" y="51" width="70" height="70"/>
|
||||
<g>
|
||||
<rect x="75.038" y="107.8746" width="26.2498" height="4.375" fill="#fff"/>
|
||||
<g>
|
||||
<path d="M74.7429,69.4315L76.78,67.5082a2.31,2.31,0,0,0,1.7929,1.0594A1.33,1.33,0,0,0,79.8607,66.97V59.75h3.1456v7.2366a4.2386,4.2386,0,0,1-1.1246,3.2108,4.2989,4.2989,0,0,1-3.1293,1.1572A4.6592,4.6592,0,0,1,74.7429,69.4315Z" fill="#fff"/>
|
||||
<path d="M83.7394,59.75h9.1761v2.673H86.8688v1.744H92.345v2.4937H86.8688V68.47H92.997v2.6893H83.7394V59.75Z" fill="#fff"/>
|
||||
<path d="M97.049,62.5208H93.6426V59.75h9.9911v2.7708h-3.4227v8.6383H97.049V62.5208Z" fill="#fff"/>
|
||||
<path d="M75.0363,73.8257h5.8511A4.2728,4.2728,0,0,1,84,74.8363a2.5675,2.5675,0,0,1,.7335,1.858v0.0326a2.6407,2.6407,0,0,1-1.76,2.5425,2.7686,2.7686,0,0,1,2.2655,2.7871v0.0326c0,1.9558-1.5973,3.1456-4.3191,3.1456H75.0363V73.8257Zm6.5846,3.5206c0-.6357-0.5052-0.9779-1.4343-0.9779h-2.07v2.0047h1.9884c0.9616,0,1.5158-.326,1.5158-0.9942V77.3463ZM80.5289,80.59H78.1166v2.1025h2.4448c0.9779,0,1.5158-.3749,1.5158-1.0431V81.6165C82.0773,80.9972,81.5883,80.59,80.5289,80.59Z" fill="#fff"/>
|
||||
<path d="M85.7116,73.8257h5.3949a5.0512,5.0512,0,0,1,3.7161,1.2224,3.5623,3.5623,0,0,1,1.01,2.6567v0.0326a3.6146,3.6146,0,0,1-2.3469,3.5205l2.7218,3.9769H92.5733l-2.2981-3.4553H88.8735v3.4553H85.7116V73.8257Zm5.2644,5.4764a1.433,1.433,0,0,0,1.6951-1.3528V77.9167c0-.9128-0.6682-1.3691-1.7114-1.3691H88.8735v2.7545H90.976Z" fill="#fff"/>
|
||||
<path d="M99.5324,73.7443H102.58l4.8571,11.4905h-3.39l-0.815-2.0536H98.8153L98,85.2348H94.6917Zm2.7707,6.9758-1.2712-3.2271L99.7443,80.72h2.5589Z" fill="#fff"/>
|
||||
<path d="M107.8117,73.8257h3.1619V85.2348h-3.1619V73.8257Z" fill="#fff"/>
|
||||
<path d="M111.7558,73.8257h2.95l4.694,6.0306V73.8257h3.1294V85.2348h-2.7545l-4.89-6.2587v6.2587h-3.1293V73.8257Z" fill="#fff"/>
|
||||
<path d="M122.7274,83.54l1.76-2.1025a5.9106,5.9106,0,0,0,3.7,1.3691c0.8638,0,1.32-.2934,1.32-0.7824V81.9914c0-.489-0.3749-0.7335-1.9395-1.1084-2.4285-.5541-4.3029-1.2387-4.3029-3.5694V77.2811c0-2.1188,1.6788-3.6509,4.417-3.6509a7.1807,7.1807,0,0,1,4.694,1.5158l-1.5809,2.2329a5.6006,5.6006,0,0,0-3.1946-1.1246c-0.766,0-1.1409.31-1.1409,0.7334V77.02c0,0.5216.3912,0.75,1.9884,1.1083,2.6077,0.57,4.2377,1.418,4.2377,3.5531v0.0326c0,2.3307-1.8418,3.7161-4.6126,3.7161A7.9992,7.9992,0,0,1,122.7274,83.54Z" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
39
scripts/download.ps1
Normal file
39
scripts/download.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
param([string]$OutputPath)
|
||||
|
||||
$NetchDataURL="https://github.com/NetchX/NetchData/archive/refs/heads/master.zip"
|
||||
$NetchModeURL="https://github.com/NetchX/NetchMode/archive/refs/heads/master.zip"
|
||||
$NetchI18NURL="https://github.com/NetchX/NetchI18N/archive/refs/heads/master.zip"
|
||||
|
||||
$last=$(Get-Location)
|
||||
New-Item -ItemType Directory -Name $OutputPath | Out-Null
|
||||
Set-Location $OutputPath
|
||||
|
||||
Invoke-WebRequest -Uri $NetchDataURL -OutFile data.zip
|
||||
Invoke-WebRequest -Uri $NetchModeURL -OutFile mode.zip
|
||||
Invoke-WebRequest -Uri $NetchI18NURL -OutFile i18n.zip
|
||||
|
||||
Expand-Archive -Force -Path data.zip -DestinationPath .
|
||||
Expand-Archive -Force -Path mode.zip -DestinationPath .
|
||||
Expand-Archive -Force -Path i18n.zip -DestinationPath .
|
||||
|
||||
New-Item -ItemType Directory -Name bin | Out-Null
|
||||
New-Item -ItemType Directory -Name mode | Out-Null
|
||||
New-Item -ItemType Directory -Name i18n | Out-Null
|
||||
|
||||
Copy-Item -Recurse -Force .\NetchData-master\* .\bin
|
||||
Copy-Item -Recurse -Force .\NetchMode-master\mode\* .\mode
|
||||
Copy-Item -Recurse -Force .\NetchI18N-master\i18n\* .\i18n
|
||||
|
||||
Remove-Item -Recurse -Force NetchData-master
|
||||
Remove-Item -Recurse -Force NetchMode-master
|
||||
Remove-Item -Recurse -Force NetchI18N-master
|
||||
Remove-Item -Force data.zip
|
||||
Remove-Item -Force mode.zip
|
||||
Remove-Item -Force i18n.zip
|
||||
|
||||
..\scripts\download\cloak.ps1 -OutputPath bin
|
||||
..\scripts\download\xray-core.ps1 -OutputPath bin
|
||||
|
||||
Get-Item *
|
||||
Set-Location $last
|
||||
exit 0
|
||||
7
scripts/download/cloak.ps1
Normal file
7
scripts/download/cloak.ps1
Normal file
@@ -0,0 +1,7 @@
|
||||
param([string]$OutputPath)
|
||||
$address="https://github.com/cbeuw/Cloak/releases/download/v2.5.4/ck-client-windows-amd64-v2.5.4.exe"
|
||||
|
||||
Invoke-WebRequest -Uri $address -OutFile ck-client.exe
|
||||
|
||||
Move-Item -Force ck-client.exe $OutputPath
|
||||
exit 0
|
||||
13
scripts/download/xray-core.ps1
Normal file
13
scripts/download/xray-core.ps1
Normal file
@@ -0,0 +1,13 @@
|
||||
param([string]$OutputPath)
|
||||
$address="https://github.com/XTLS/Xray-core/releases/download/v1.4.2/Xray-windows-64.zip"
|
||||
|
||||
Invoke-WebRequest -Uri $address -OutFile xray-core.zip
|
||||
Expand-Archive -Force -Path xray-core.zip -DestinationPath xray-core
|
||||
|
||||
Move-Item -Force xray-core\xray.exe $OutputPath
|
||||
Move-Item -Force xray-core\geoip.dat $OutputPath
|
||||
Move-Item -Force xray-core\geosite.dat $OutputPath
|
||||
|
||||
Remove-Item -Recurse -Force xray-core
|
||||
Remove-Item -Recurse -Force xray-core.zip
|
||||
exit 0
|
||||
Reference in New Issue
Block a user