Compare commits

...

19 Commits
1.6.9 ... 1.7.0

Author SHA1 Message Date
AmazingDM
ac2e5e943e Update mode 2021-01-04 14:05:15 +08:00
AmazingDM
0957514e05 Bump version to 1.7.0 2021-01-04 14:01:20 +08:00
AmazingDM
35b9f168ff 添加测速方式(TCPing&ICMPing)切换设置选项 2021-01-04 13:59:19 +08:00
AmazingDM
ce15e9468e 不代理TCP流量设置
调整设置界面UI
2021-01-04 13:23:58 +08:00
AmazingDM
4c8508a838 Merge remote-tracking branch 'chsbuffer/fixJob' 2021-01-04 12:45:19 +08:00
ChsBuffer
f931adb005 Fix TrojanController ignores sni (host) value
closes #478, #487
2020-12-31 15:04:53 +08:00
Connection Refused
d4f829d4bd Merge pull request #486 from SekiBetu/dev
set mux to false by default
2020-12-30 09:26:44 +08:00
SekiBetu
51d4ba0fdb set mux to false by default 2020-12-30 06:37:02 +08:00
AmazingDM
ca0870889a 更新NTT,优化部分代码 2020-12-28 15:21:43 +08:00
ChsBuffer
ac3e39e9cd Update AioDNS 2020-12-25 22:44:44 +08:00
ChsBuffer
84765ab96d Delay Add Job 2020-12-25 17:12:03 +08:00
AmazingDM
a18851af15 Update binaries 2020-12-25 13:48:40 +08:00
AmazingDM
42366abcca Update README.md Quote 2020-12-25 13:43:33 +08:00
AmazingDM
cec8358922 PAC 2020-12-25 11:28:38 +08:00
AmazingDM
db8e964351 Update translations 2020-12-25 09:43:48 +08:00
AmazingDM
ad3053298a PAC替换ACL
sysproxy.dll 替换为 nuget WindowsProxy
2020-12-24 22:57:52 +08:00
ChsBuffer
669ca4902f Fix: set encoding only when RedireStd enabled 2020-12-24 16:14:41 +08:00
ChsBuffer
272bf61b0f Remove RedirecStandInput (Fix SS plugin start error) 2020-12-24 15:59:51 +08:00
ChsBuffer
0051e7bb50 Feat ICMPing 2020-12-24 13:32:06 +08:00
32 changed files with 1003 additions and 477 deletions

View File

@@ -6,7 +6,6 @@ namespace Netch.Controllers
{
public class DNSController : IController
{
public string Name { get; } = "DNS Service";
/// <summary>
@@ -15,13 +14,14 @@ namespace Netch.Controllers
/// <returns></returns>
public bool Start()
{
if (!aiodns_dial(Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)),
Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"),
Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"))
)
return false;
return
aiodns_init();
aiodns_dial((int) NameList.TYPE_REST, null);
aiodns_dial((int) NameList.TYPE_ADDR, Encoding.UTF8.GetBytes($"{Global.Settings.LocalAddress}:53"));
aiodns_dial((int) NameList.TYPE_LIST, Encoding.UTF8.GetBytes(Path.GetFullPath(Global.Settings.AioDNS.RulePath)));
aiodns_dial((int) NameList.TYPE_CDNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.ChinaDNS}:53"));
aiodns_dial((int) NameList.TYPE_ODNS, Encoding.UTF8.GetBytes($"{Global.Settings.AioDNS.OtherDNS}:53"));
aiodns_dial((int) NameList.TYPE_METH, Encoding.UTF8.GetBytes(Global.Settings.AioDNS.Protocol));
return aiodns_init();
}
public void Stop()
@@ -32,7 +32,7 @@ namespace Netch.Controllers
#region NativeMethods
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aiodns_dial(byte[] chinacon, byte[] chinadns, byte[] otherdns);
public static extern bool aiodns_dial(int name, byte[] value);
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern bool aiodns_init();
@@ -40,6 +40,16 @@ namespace Netch.Controllers
[DllImport("aiodns.bin", CallingConvention = CallingConvention.Cdecl)]
public static extern void aiodns_free();
enum NameList : int
{
TYPE_REST,
TYPE_ADDR,
TYPE_LIST,
TYPE_CDNS,
TYPE_ODNS,
TYPE_METH
}
#endregion
}
}

View File

@@ -56,7 +56,7 @@ namespace Netch.Controllers
/// 程序输出的编码,
/// 调用于基类的 <see cref="OnOutputDataReceived"/>
/// </summary>
protected string InstanceOutputEncoding { get; set; } = "gbk";
protected Encoding InstanceOutputEncoding { get; set; } = Encoding.GetEncoding("gbk");
/// <summary>
/// 停止进程
@@ -93,10 +93,11 @@ namespace Netch.Controllers
WorkingDirectory = $"{Global.NetchDir}\\bin",
Arguments = argument,
CreateNoWindow = true,
RedirectStandardError = RedirectStd,
RedirectStandardInput = RedirectStd,
RedirectStandardOutput = RedirectStd,
UseShellExecute = !RedirectStd,
RedirectStandardOutput = RedirectStd,
StandardOutputEncoding = RedirectStd ? InstanceOutputEncoding : null,
RedirectStandardError = RedirectStd,
StandardErrorEncoding = RedirectStd ? InstanceOutputEncoding : null,
WindowStyle = ProcessWindowStyle.Hidden
}
};
@@ -192,15 +193,13 @@ namespace Netch.Controllers
if (e.Data == null)
return;
var info = Encoding.GetEncoding(InstanceOutputEncoding).GetBytes(e.Data);
var str = Encoding.UTF8.GetString(info);
Write(str);
Write(e.Data);
// 检查启动
if (State == State.Starting)
{
if (StartedKeywords.Any(s => str.Contains(s)))
if (StartedKeywords.Any(s => e.Data.Contains(s)))
State = State.Started;
else if (StoppedKeywords.Any(s => str.Contains(s)))
else if (StoppedKeywords.Any(s => e.Data.Contains(s)))
State = State.Stopped;
}
}

View File

@@ -4,8 +4,9 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils;
using WindowsProxy;
using Netch.Utils.HttpProxyHandler;
namespace Netch.Controllers
{
@@ -36,7 +37,23 @@ namespace Netch.Controllers
Global.Job.AddProcess(pPrivoxyController.Instance);
}
if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions);
if (mode.Type == 3)
{
if (mode.BypassChina)
{
//启动PAC服务器
PACServerHandle.InitPACServer("127.0.0.1");
}
else
{
using var service = new ProxyService
{
Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}",
Bypass = IEProxyExceptions
};
service.Global();
}
}
}
catch (Exception e)
{
@@ -85,18 +102,36 @@ namespace Netch.Controllers
{
var tasks = new[]
{
Task.Factory.StartNew(pPrivoxyController.Stop),
Task.Factory.StartNew(() =>
Task.Run(pPrivoxyController.Stop),
Task.Run(() =>
{
if (prevEnabled)
using var service = new ProxyService();
try
{
if (prevHTTP != "")
NativeMethods.SetGlobal(prevHTTP, prevBypass);
if (prevPAC != "")
NativeMethods.SetURL(prevPAC);
PACServerHandle.Stop();
if (prevEnabled)
{
if (prevHTTP != "")
{
service.Server = prevHTTP;
service.Bypass = prevBypass;
service.Global();
}
if (prevPAC != "")
{
service.AutoConfigUrl = prevPAC;
service.Pac();
}
}
else
{
service.Direct();
}
}
catch (Exception e)
{
Logging.Error($"{Name} 控制器出错:\n" + e);
}
else
NativeMethods.SetDIRECT();
})
};
Task.WaitAll(tasks);

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Netch.Models;
using Netch.Servers.Socks5;
@@ -149,7 +150,11 @@ namespace Netch.Controllers
{
if (guard.Instance != null)
{
Global.Job.AddProcess(guard.Instance);
Task.Run(() =>
{
Thread.Sleep(1000);
Global.Job.AddProcess(guard.Instance);
});
}
}

View File

@@ -55,8 +55,11 @@ namespace Netch.Controllers
#region aio_dial
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp) MessageBoxX.Show("");
//UDP
if (Global.Settings.ProcessNoProxyForUdp)
{
aio_dial((int) NameList.TYPE_FILTERUDP, "false");
@@ -68,6 +71,18 @@ namespace Netch.Controllers
SetServer(PortType.Both);
}
//TCP
if (Global.Settings.ProcessNoProxyForTcp)
{
aio_dial((int) NameList.TYPE_FILTERTCP, "false");
SetServer(PortType.UDP);
}
else
{
aio_dial((int) NameList.TYPE_FILTERTCP, "true");
SetServer(PortType.Both);
}
if (!CheckRule(mode.FullRule, out var list))
{
MessageBoxX.Show($"\"{string.Join("", list.Select(s => s + "\n"))}\" does not conform to C++ regular expression syntax");

View File

@@ -2,6 +2,7 @@
using System.Text;
using Netch.Models;
using Netch.Servers.Socks5;
using Netch.Utils.HttpProxyHandler;
namespace Netch.Controllers
{

View File

@@ -119,9 +119,9 @@ namespace Netch.Controllers
{
var tasks = new[]
{
Task.Factory.StartNew(StopInstance),
Task.Factory.StartNew(ClearRouteTable),
Task.Factory.StartNew(DNSController.Stop)
Task.Run(StopInstance),
Task.Run(ClearRouteTable),
Task.Run(DNSController.Stop)
};
Task.WaitAll(tasks);
}

View File

@@ -16,7 +16,7 @@ namespace Netch.Controllers
public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2020";
public const string AssemblyVersion = @"1.6.9";
public const string AssemblyVersion = @"1.7.0";
private const string Suffix = @"";
public static readonly string Version = $"{AssemblyVersion}{(string.IsNullOrEmpty(Suffix) ? "" : $"-{Suffix}")}";

View File

@@ -87,6 +87,7 @@
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.ButtomControlContainerControl = new System.Windows.Forms.ContainerControl();
this.updatePACToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MenuStrip.SuspendLayout();
this.ConfigurationGroupBox.SuspendLayout();
this.configLayoutPanel.SuspendLayout();
@@ -196,6 +197,7 @@
this.CleanDNSCacheToolStripMenuItem,
this.UpdateACLToolStripMenuItem,
this.updateACLWithProxyToolStripMenuItem,
this.updatePACToolStripMenuItem,
this.UninstallServiceToolStripMenuItem,
this.UninstallTapDriverToolStripMenuItem});
this.OptionsToolStripMenuItem.Margin = new System.Windows.Forms.Padding(0, 0, 0, 1);
@@ -697,6 +699,13 @@
this.ButtomControlContainerControl.TabStop = false;
this.ButtomControlContainerControl.Text = "groupBox1";
//
// updatePACToolStripMenuItem
//
this.updatePACToolStripMenuItem.Name = "updatePACToolStripMenuItem";
this.updatePACToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.updatePACToolStripMenuItem.Text = "Update PAC";
this.updatePACToolStripMenuItem.Click += new System.EventHandler(this.updatePACToolStripMenuItem_Click);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -803,5 +812,6 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ContainerControl ButtomControlContainerControl;
private System.Windows.Forms.ToolStripMenuItem updatePACToolStripMenuItem;
}
}

View File

@@ -3,12 +3,16 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Netch.Controllers;
using Netch.Forms.Mode;
using Netch.Models;
using Netch.Properties;
using Netch.Utils;
using Netch.Utils.HttpProxyHandler;
using Newtonsoft.Json;
namespace Netch.Forms
{
@@ -274,6 +278,39 @@ namespace Netch.Forms
}
}
private async void updatePACToolStripMenuItem_Click(object sender, EventArgs eventArgs)
{
Enabled = false;
NotifyTip(i18N.Translate("Updating in the background"));
try
{
var req = WebUtil.CreateRequest(Global.Settings.GFWLIST);
string gfwlist = Path.Combine(Global.NetchDir, $"bin\\gfwlist");
string pac = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
await WebUtil.DownloadFileAsync(req, gfwlist);
var gfwContent = File.ReadAllText(gfwlist);
List<string> lines = PACUtil.ParseResult(gfwContent);
string abpContent = PACUtil.UnGzip(Resources.abp_js);
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
File.WriteAllText(pac, abpContent, Encoding.UTF8);
NotifyTip(i18N.Translate("PAC updated successfully"));
}
catch (Exception e)
{
NotifyTip(i18N.Translate("PAC update failed") + "\n" + e.Message, info: false);
Logging.Error("更新 PAC 失败!" + e);
}
finally
{
Enabled = true;
}
}
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;

File diff suppressed because it is too large Load Diff

View File

@@ -59,6 +59,14 @@ namespace Netch.Forms
c => Global.Settings.ResolveServerHostname = c,
Global.Settings.ResolveServerHostname);
BindRadioBox(ICMPingRadioBtn,
c => Global.Settings.ServerTCPing = c,
!Global.Settings.ServerTCPing);
BindRadioBox(TCPingRadioBtn,
c => Global.Settings.ServerTCPing = c,
Global.Settings.ServerTCPing);
BindTextBox<int>(ProfileCountTextBox,
i => i > -1,
i => Global.Settings.ProfileCount = i,
@@ -105,6 +113,10 @@ namespace Netch.Forms
s => Global.Settings.ProcessNoProxyForUdp = s,
Global.Settings.ProcessNoProxyForUdp);
BindCheckBox(NoProxyForTcpCheckBox,
s => Global.Settings.ProcessNoProxyForTcp = s,
Global.Settings.ProcessNoProxyForTcp);
#endregion
#region TUN/TAP
@@ -310,10 +322,11 @@ namespace Netch.Forms
return;
}
#endregion
#region CheckSTUN
var stunFlag = true;
var errFlag = false;
var stunServer = string.Empty;
ushort stunServerPort = 3478;
@@ -325,15 +338,15 @@ namespace Netch.Forms
if (stun.Length > 1)
if (!ushort.TryParse(stun[1], out stunServerPort))
{
stunFlag = false;
errFlag = true;
}
}
else
{
stunFlag = false;
errFlag = true;
}
if (!stunFlag)
if (errFlag)
{
Utils.Utils.ChangeControlForeColor(STUN_ServerComboBox, Color.Red);
return;
@@ -341,8 +354,6 @@ namespace Netch.Forms
#endregion
#endregion
#region Save
foreach (var pair in _saveActions)
@@ -418,7 +429,13 @@ namespace Netch.Forms
{
control.Checked = value;
_checkActions.Add(control, s => true);
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
_saveActions.Add(control, c => save.Invoke(((CheckBox)c).Checked));
}
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
{
control.Checked = value;
_checkActions.Add(control, s => true);
_saveActions.Add(control, c => save.Invoke(((RadioButton)c).Checked));
}
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
@@ -429,5 +446,25 @@ namespace Netch.Forms
{
ModifiedDNSTextBox.Enabled = ModifySystemDNSCheckBox.Checked;
}
private void NoProxyForUdpCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (NoProxyForUdpCheckBox.Checked) NoProxyForTcpCheckBox.Checked = false;
}
private void NoProxyForTcpCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (NoProxyForTcpCheckBox.Checked) NoProxyForUdpCheckBox.Checked = false;
}
private void ICMPingRadioBtn_CheckedChanged(object sender, EventArgs e)
{
if (ICMPingRadioBtn.Checked) TCPingRadioBtn.Checked = false;
}
private void TCPingRadioBtn_CheckedChanged(object sender, EventArgs e)
{
if (TCPingRadioBtn.Checked) ICMPingRadioBtn.Checked = false;
}
}
}

View File

@@ -4,7 +4,7 @@ using Netch.Utils;
namespace Netch.Models
{
public class Server:ICloneable
public class Server : ICloneable
{
/// <summary>
/// 备注
@@ -81,7 +81,7 @@ namespace Netch.Models
{
try
{
return await Utils.Utils.TCPingAsync(destination, Port);
return Global.Settings.ServerTCPing ? await Utils.Utils.TCPingAsync(destination, Port) : await Utils.Utils.ICMPing(destination, Port);
}
catch (Exception)
{

View File

@@ -68,7 +68,7 @@ namespace Netch.Models
public KcpConfig KcpConfig = new KcpConfig();
public bool UseMux = true;
public bool UseMux = false;
}
public class AioDNSConfig
@@ -78,6 +78,8 @@ namespace Netch.Models
public string ChinaDNS = "223.5.5.5";
public string OtherDNS = "1.1.1.1";
public string Protocol = "tcp";
}
/// <summary>
@@ -85,6 +87,11 @@ namespace Netch.Models
/// </summary>
public class Setting
{
public V2rayConfig V2RayConfig = new V2rayConfig();
public AioDNSConfig AioDNS = new AioDNSConfig();
/// <summary>
/// 服务器选择位置
/// </summary>
@@ -155,6 +162,16 @@ namespace Netch.Models
/// </summary>
public int RequestTimeout = 10000;
/// <summary>
/// PAC URL
/// </summary>
public string Pac_Url = "";
/// <summary>
/// PAC端口
/// </summary>
public int Pac_Port = 2803;
/// <summary>
/// HTTP 本地端口
/// </summary>
@@ -240,6 +257,11 @@ namespace Netch.Models
/// </summary>
public string ACL = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/banAD.acl";
/// <summary>
/// GFWList
/// </summary>
public string GFWLIST = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";
/// <summary>
/// 是否使用DLL启动Shadowsocks
/// </summary>
@@ -250,12 +272,24 @@ namespace Netch.Models
/// </summary>
public string Language = "System";
public V2rayConfig V2RayConfig = new V2rayConfig();
public AioDNSConfig AioDNS = new AioDNSConfig();
/// <summary>
/// 服务器测试方式 false.ICMPing true.TCPing
/// </summary>
public bool ServerTCPing = true;
/// <summary>
/// 是否使用RDR内置SS
/// </summary>
public bool RedirectorSS = false;
/// <summary>
/// 不代理UDP
/// </summary>
public bool ProcessNoProxyForUdp = false;
/// <summary>
/// 不代理TCP
/// </summary>
public bool ProcessNoProxyForTcp = false;
}
}

View File

@@ -28,30 +28,6 @@ namespace Netch
[DllImport("NetchCore", CallingConvention = CallingConvention.Cdecl, EntryPoint = "DeleteRoute")]
public static extern bool DeleteRoute(string address, int cidr, string gateway, int index, int metric = 0);
/// <summary>
/// 设置直连
/// </summary>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetDIRECT();
/// <summary>
/// 设置全局
/// </summary>
/// <param name="remote">地址</param>
/// <param name="bypass">绕过</param>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetGlobal([MarshalAs(UnmanagedType.LPTStr)] string remote, [MarshalAs(UnmanagedType.LPTStr)] string bypass);
/// <summary>
/// 设置自动代理
/// </summary>
/// <param name="remote">URL</param>
/// <returns>是否成功</returns>
[DllImport("sysproxy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool SetURL([MarshalAs(UnmanagedType.LPTStr)] string remote);
[DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]
public static extern uint FlushDNSResolverCache();

View File

@@ -66,13 +66,14 @@
<ItemGroup>
<PackageReference Include="ILMerge" Version="3.0.41" />
<PackageReference Include="MaxMind.GeoIP2" Version="3.3.0" />
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.62" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
<PackageReference Include="WindowsAPICodePack-Shell" Version="1.1.1" />
<PackageReference Include="WindowsJobAPI" Version="5.0.0" />
<PackageReference Include="WindowsJobAPI" Version="5.0.1" />
<PackageReference Include="WindowsProxy" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -60,6 +60,16 @@ namespace Netch.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] abp_js {
get {
object obj = ResourceManager.GetObject("abp_js", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@@ -1,145 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<assembly alias="System.Windows.Forms"
name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</data>
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
<data name="abp_js" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\abp.js.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a
</value>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="defaultTUNTAP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\defaultTUNTAP;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="zh_CN" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\zh-CN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="speed" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\speed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="delete" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Netch" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Netch.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Sponsor" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Sponsor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="CopyLink" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CopyLink.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

BIN
Netch/Resources/abp.js.gz Normal file

Binary file not shown.

View File

@@ -81,10 +81,16 @@
"Modes have been reload": "模式已重载",
"Clean DNS Cache": "清理 DNS 缓存",
"DNS cache cleanup succeeded": "DNS 缓存清理成功",
"Update PAC": "更新 PAC",
"PAC updated successfully": "PAC 更新成功",
"PAC update failed": "PAC 更新失败",
"Update ACL": "更新 ACL 规则",
"Update ACL with proxy": "使用代理更新 ACL 规则",
"ACL updated successfully": "ACL 更新成功",
"ACL update failed": "ACL 更新失败",
"Open Directory": "打开目录",
"About": "关于",
@@ -156,6 +162,7 @@
"SS DLL": "SS DLL",
"Modify System DNS": "修改系统 DNS",
"No Proxy for Udp": "不代理Udp流量",
"No Proxy for Tcp": "不代理Tcp流量",
"ProfileCount": "快捷配置数量",
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",
"STUN_ServerPort value illegal. Try again.": "STUN 端口数值非法。请重试。",
@@ -164,6 +171,7 @@
"Failed to set the system proxy, it may be caused by the lack of dependent programs. Do you want to jump to Netch's official website to download dependent programs?": "设置系统代理失败,可能是缺少依赖导致,是否跳转 Netch 官网下载依赖程序?",
"Delay test after start": "启动后延迟测试",
"Enable": "启用",
"ServerPingType": "测速方式",
"Detection interval(sec)": "检测间隔(秒)",
"STUN Server": "STUN 服务器",
"STUN Server Port": "STUN 服务器端口",

View File

@@ -25,7 +25,7 @@ namespace Netch.Servers.Trojan
public bool Start(in Server s, in Mode mode)
{
var server = (Trojan) s;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(new TrojanConfig
var trojanConfig = new TrojanConfig
{
local_addr = this.LocalAddress(),
local_port = this.Socks5LocalPort(),
@@ -35,8 +35,15 @@ namespace Netch.Servers.Trojan
{
server.Password
}
}));
};
if (!string.IsNullOrWhiteSpace(server.Host))
trojanConfig.ssl.sni = server.Host;
File.WriteAllText("data\\last.json", JsonConvert.SerializeObject(trojanConfig, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
return StartInstanceAuto("-c ..\\data\\last.json");
}

View File

@@ -70,7 +70,7 @@ namespace Netch.Servers.VMess
/// <summary>
/// Mux 多路复用
/// </summary>
public bool? UseMux { get; set; } = true;
public bool? UseMux { get; set; } = false;
}
public class VMessGlobal

View File

@@ -0,0 +1,99 @@
using System;
using System.Net;
using System.Text;
using System.Threading;
namespace Netch.Utils.HttpProxyHandler
{
public class HttpWebServer
{
private HttpListener _listener;
private Func<HttpListenerRequest, string> _responderMethod;
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
{
try
{
_listener = new HttpListener();
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required, for example
// "http://localhost:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
_listener.Prefixes.Add(s);
_responderMethod = method;
_listener.Start();
}
catch (Exception ex)
{
Logging.Error("HttpWebServer():" + ex.Message);
}
}
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
: this(prefixes, method)
{
}
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Logging.Info("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.StatusCode = 200;
ctx.Response.ContentType = "application/x-ns-proxy-autoconfig";
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch
{
} // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch (Exception ex)
{
//Logging.Error(ex.Message, ex);
Logging.Error(ex.Message);
} // suppress any exceptions
});
}
public void Stop()
{
if (_listener != null)
{
_listener.Stop();
_listener.Close();
_listener = null;
}
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
using WindowsProxy;
namespace Netch.Utils.HttpProxyHandler
{
/// <summary>
/// 提供PAC功能支持
/// </summary>
class PACServerHandle
{
private static Hashtable httpWebServer = new Hashtable();
private static Hashtable pacList = new Hashtable();
public static void InitPACServer(string address)
{
try
{
if (!pacList.ContainsKey(address))
{
pacList.Add(address, GetPacList(address));
}
string prefixes = string.Format("http://{0}:{1}/pac/", address, Global.Settings.Pac_Port);
HttpWebServer ws = new HttpWebServer(SendResponse, prefixes);
ws.Run();
if (!httpWebServer.ContainsKey(address) && ws != null)
{
httpWebServer.Add(address, ws);
}
Global.Settings.Pac_Url = GetPacUrl();
using var service = new ProxyService
{
AutoConfigUrl = Global.Settings.Pac_Url
};
service.Pac();
Logging.Info(service.Set(service.Query()) + "");
Logging.Info($"Webserver InitServer OK: {Global.Settings.Pac_Url}");
}
catch (Exception ex)
{
Logging.Error("Webserver InitServer " + ex.Message);
}
}
public static string SendResponse(HttpListenerRequest request)
{
try
{
string[] arrAddress = request.UserHostAddress.Split(':');
string address = "127.0.0.1";
if (arrAddress.Length > 0)
{
address = arrAddress[0];
}
return pacList[address].ToString();
}
catch (Exception ex)
{
Logging.Error("Webserver SendResponse " + ex.Message);
return ex.Message;
}
}
public static void Stop()
{
try
{
if (httpWebServer == null)
{
return;
}
foreach (var key in httpWebServer.Keys)
{
Logging.Info("Webserver Stop " + key.ToString());
((HttpWebServer)httpWebServer[key]).Stop();
}
httpWebServer.Clear();
}
catch (Exception ex)
{
Logging.Error("Webserver Stop " + ex.Message);
}
}
private static string GetPacList(string address)
{
try
{
List<string> lstProxy = new List<string>();
lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort));
var proxy = string.Join("", lstProxy.ToArray());
string strPacfile = Path.Combine(Global.NetchDir, $"bin\\pac.txt");
var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy);
return pac;
}
catch
{ }
return "No pac content";
}
/// <summary>
/// 获取PAC地址
/// </summary>
/// <returns></returns>
public static string GetPacUrl()
{
string pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port,
DateTime.Now.ToString("yyyyMMddHHmmssfff"));
return pacUrl;
}
}
}

View File

@@ -0,0 +1,56 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using Netch.Forms;
using Netch.Properties;
namespace Netch.Utils.HttpProxyHandler
{
/// <summary>
/// 提供PAC功能支持
/// </summary>
class PACUtil
{
private static readonly IEnumerable<char> IgnoredLineBegins = new[] {'!', '['};
public static List<string> ParseResult(string response)
{
byte[] bytes = Convert.FromBase64String(response);
string content = Encoding.ASCII.GetString(bytes);
List<string> valid_lines = new List<string>();
using (var sr = new StringReader(content))
{
foreach (var line in sr.NonWhiteSpaceLines())
{
if (line.BeginWithAny(IgnoredLineBegins))
continue;
valid_lines.Add(line);
}
}
return valid_lines;
}
public static string UnGzip(byte[] buf)
{
byte[] buffer = new byte[1024];
int n;
using (MemoryStream sb = new MemoryStream())
{
using (GZipStream input = new GZipStream(new MemoryStream(buf),
CompressionMode.Decompress,
false))
{
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
{
sb.Write(buffer, 0, n);
}
}
return System.Text.Encoding.UTF8.GetString(sb.ToArray());
}
}
}
}

46
Netch/Utils/StringEx.cs Normal file
View File

@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Netch.Utils
{
static class StringEx
{
public static bool IsNullOrEmpty(this string value)
{
return string.IsNullOrEmpty(value);
}
public static bool IsNullOrWhiteSpace(this string value)
{
return string.IsNullOrWhiteSpace(value);
}
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
{
if (s.IsNullOrEmpty()) return false;
return chars.Contains(s[0]);
}
public static bool IsWhiteSpace(this string value)
{
foreach (var c in value)
{
if (char.IsWhiteSpace(c)) continue;
return false;
}
return true;
}
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.IsWhiteSpace()) continue;
yield return line;
}
}
}
}

View File

@@ -56,6 +56,18 @@ namespace Netch.Utils
return timeout;
}
public static async Task<int> ICMPing(IPAddress ip, int timeout = 1000)
{
var reply = new Ping().Send(ip, timeout);
if (reply?.Status == IPStatus.Success)
{
return Convert.ToInt32(reply.RoundtripTime);
}
return timeout;
}
public static string GetCityCode(string Hostname)
{
if (Hostname.Contains(":"))

View File

@@ -63,6 +63,7 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
- [v2ray-core](https://github.com/v2ray/v2ray-core)
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [GFWList](https://github.com/gfwlist/gfwlist)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)

View File

@@ -72,6 +72,7 @@ Netch 支持多种语言,在启动时会根据系统语言选择自身语言
- [v2ray-core](https://github.com/v2ray/v2ray-core)
- [trojan](https://github.com/trojan-gfw/trojan)
- [ACL4SSR](https://github.com/ACL4SSR/ACL4SSR)
- [GFWList](https://github.com/gfwlist/gfwlist)
- [dnsmasq-china-list](https://github.com/felixonmars/dnsmasq-china-list)
- [tap-windows6](https://github.com/OpenVPN/tap-windows6)
- [Privoxy](https://www.privoxy.org/)

2
modes

Submodule modes updated: 90ffd0c66a...e3ae0d5406