mirror of
https://github.com/netchx/netch.git
synced 2026-05-11 23:45:06 +08:00
Reformat
This commit is contained in:
@@ -67,7 +67,9 @@ namespace Netch.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Instance == null || Instance.HasExited) return;
|
||||
if (Instance == null || Instance.HasExited)
|
||||
return;
|
||||
|
||||
Instance.Kill();
|
||||
Instance.WaitForExit();
|
||||
}
|
||||
@@ -134,7 +136,10 @@ namespace Netch.Controllers
|
||||
Instance.Start();
|
||||
if (priority != ProcessPriorityClass.Normal)
|
||||
Instance.PriorityClass = priority;
|
||||
if (!RedirectStd) return;
|
||||
|
||||
if (!RedirectStd)
|
||||
return;
|
||||
|
||||
// 启动日志重定向
|
||||
Instance.BeginOutputReadLine();
|
||||
Instance.BeginErrorReadLine();
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace Netch.Controllers
|
||||
Server = $"127.0.0.1:{Global.Settings.HTTPLocalPort}",
|
||||
Bypass = string.Join(";", ProxyService.LanIp)
|
||||
};
|
||||
|
||||
service.Global();
|
||||
}
|
||||
}
|
||||
@@ -72,6 +73,7 @@ namespace Netch.Controllers
|
||||
service.Bypass = prevBypass;
|
||||
service.Global();
|
||||
}
|
||||
|
||||
if (prevPAC != "")
|
||||
{
|
||||
service.AutoConfigUrl = prevPAC;
|
||||
@@ -89,6 +91,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@ namespace Netch.Controllers
|
||||
Task.Run(() => ServerController?.Stop()),
|
||||
Task.Run(() => ModeController?.Stop())
|
||||
};
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
ModeController = null;
|
||||
ServerController = null;
|
||||
|
||||
@@ -57,7 +57,8 @@ namespace Netch.Controllers
|
||||
aio_dial((int) NameList.TYPE_FILTERLOOPBACK, "false");
|
||||
aio_dial((int) NameList.TYPE_TCPLISN, Global.Settings.RedirectorTCPPort.ToString());
|
||||
|
||||
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp) MessageBoxX.Show("?");
|
||||
if (Global.Settings.ProcessNoProxyForUdp && Global.Settings.ProcessNoProxyForTcp)
|
||||
MessageBoxX.Show("?");
|
||||
|
||||
//UDP
|
||||
if (Global.Settings.ProcessNoProxyForUdp)
|
||||
@@ -96,6 +97,7 @@ namespace Netch.Controllers
|
||||
_sysDns = DNS.OutboundDNS;
|
||||
if (string.IsNullOrWhiteSpace(Global.Settings.ModifiedDNS))
|
||||
Global.Settings.ModifiedDNS = "1.1.1.1,8.8.8.8";
|
||||
|
||||
DNS.OutboundDNS = Global.Settings.ModifiedDNS;
|
||||
}
|
||||
|
||||
@@ -138,6 +140,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
if (r.StartsWith("!"))
|
||||
return aio_dial((int) NameList.TYPE_ADDNAME, r.Substring(1));
|
||||
|
||||
return aio_dial((int) NameList.TYPE_ADDNAME, r);
|
||||
}
|
||||
finally
|
||||
@@ -177,7 +180,8 @@ namespace Netch.Controllers
|
||||
reinstallFlag = true;
|
||||
}
|
||||
|
||||
if (!reinstallFlag) return;
|
||||
if (!reinstallFlag)
|
||||
return;
|
||||
|
||||
Logging.Info("更新驱动");
|
||||
UninstallDriver();
|
||||
@@ -352,7 +356,9 @@ namespace Netch.Controllers
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!File.Exists(SystemDriver)) return true;
|
||||
if (!File.Exists(SystemDriver))
|
||||
return true;
|
||||
|
||||
NFAPI.nf_unRegisterDriver("netfilter2");
|
||||
File.Delete(SystemDriver);
|
||||
|
||||
|
||||
@@ -7,9 +7,15 @@ namespace Netch.Controllers
|
||||
{
|
||||
public class NTTController : Guard, IController
|
||||
{
|
||||
public override string Name { get; } = "NTT";
|
||||
public override string MainFile { get; protected set; } = "NTT.exe";
|
||||
|
||||
public override string Name { get; } = "NTT";
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动 NatTypeTester
|
||||
/// </summary>
|
||||
@@ -42,6 +48,7 @@ namespace Netch.Controllers
|
||||
var str = line.Split(':').Select(s => s.Trim()).ToArray();
|
||||
if (str.Length < 2)
|
||||
continue;
|
||||
|
||||
var key = str[0];
|
||||
var value = str[1];
|
||||
switch (key)
|
||||
@@ -70,6 +77,7 @@ namespace Netch.Controllers
|
||||
|
||||
if (bindingTest == "Fail")
|
||||
result = "UdpBlocked";
|
||||
|
||||
return (result, localEnd, publicEnd);
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -87,10 +95,5 @@ namespace Netch.Controllers
|
||||
return (null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
StopInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ namespace Netch.Controllers
|
||||
// 查找并安装 TAP 适配器
|
||||
if (string.IsNullOrEmpty(TUNTAP.GetComponentID()))
|
||||
AddTap();
|
||||
|
||||
SearchTapAdapter();
|
||||
|
||||
SetupRouteTable(mode);
|
||||
@@ -102,6 +103,7 @@ namespace Netch.Controllers
|
||||
Task.Run(ClearRouteTable),
|
||||
Task.Run(DNSController.Stop)
|
||||
};
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
@@ -145,9 +147,7 @@ namespace Netch.Controllers
|
||||
{
|
||||
Logging.Info("代理 → 自定义 DNS");
|
||||
if (Global.Settings.TUNTAP.UseCustomDNS)
|
||||
RouteAction(Action.Create,
|
||||
Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"),
|
||||
RouteType.TUNTAP);
|
||||
RouteAction(Action.Create, Global.Settings.TUNTAP.DNS.Select(ip => $"{ip}/32"), RouteType.TUNTAP);
|
||||
else
|
||||
RouteAction(Action.Create,
|
||||
new[] {"1.1.1.1", "8.8.8.8", "9.9.9.9", "185.222.222.222"}.Select(ip => $"{ip}/32"),
|
||||
@@ -160,14 +160,13 @@ namespace Netch.Controllers
|
||||
|
||||
// 将 TUN/TAP 网卡权重放到最高
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "netsh",
|
||||
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
);
|
||||
{
|
||||
FileName = "netsh",
|
||||
Arguments = $"interface ip set interface {Global.TUNTAP.Index} metric=0",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true
|
||||
});
|
||||
|
||||
Logging.Info("绕行 → 规则 IP");
|
||||
RouteAction(Action.Create, mode.FullRule, RouteType.Outbound);
|
||||
@@ -256,8 +255,7 @@ namespace Netch.Controllers
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType,
|
||||
int metric = 0)
|
||||
private void RouteAction(Action action, in IEnumerable<string> ipNetworks, RouteType routeType, int metric = 0)
|
||||
{
|
||||
foreach (var address in ipNetworks)
|
||||
RouteAction(action, address, routeType, metric);
|
||||
|
||||
@@ -29,7 +29,9 @@ namespace Netch.Controllers
|
||||
public static Release LatestRelease;
|
||||
|
||||
public static event EventHandler NewVersionFound;
|
||||
|
||||
public static event EventHandler NewVersionFoundFailed;
|
||||
|
||||
public static event EventHandler NewVersionNotFound;
|
||||
|
||||
public static async void Check(bool isPreRelease)
|
||||
|
||||
@@ -32,4 +32,4 @@ namespace Netch.Forms
|
||||
Process.Start("https://www.mansora.co");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,8 @@ namespace Netch.Forms
|
||||
IPListBox.Items.AddRange(Global.Settings.BypassIPs.ToArray());
|
||||
|
||||
for (var i = 32; i >= 1; i--)
|
||||
{
|
||||
PrefixComboBox.Items.Add(i);
|
||||
}
|
||||
|
||||
PrefixComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
@@ -30,13 +29,9 @@ namespace Netch.Forms
|
||||
if (!string.IsNullOrEmpty(IPTextBox.Text))
|
||||
{
|
||||
if (IPAddress.TryParse(IPTextBox.Text, out var address))
|
||||
{
|
||||
IPListBox.Items.Add(string.Format("{0}/{1}", address, PrefixComboBox.SelectedItem));
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please enter a correct IP address"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -47,26 +42,20 @@ namespace Netch.Forms
|
||||
private void DeleteButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (IPListBox.SelectedIndex != -1)
|
||||
{
|
||||
IPListBox.Items.RemoveAt(IPListBox.SelectedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Please select an IP"));
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Settings.BypassIPs.Clear();
|
||||
foreach (var ip in IPListBox.Items)
|
||||
{
|
||||
Global.Settings.BypassIPs.Add(ip as string);
|
||||
}
|
||||
|
||||
Configuration.Save();
|
||||
MessageBoxX.Show(i18N.Translate("Saved"));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ namespace Netch.Forms
|
||||
|
||||
private bool _comboBoxInitialized;
|
||||
private bool _textRecorded;
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -66,6 +67,7 @@ namespace Netch.Forms
|
||||
Size = new Size(259, 22),
|
||||
Text = i18N.TranslateFormat("Add [{0}] Server", fullName)
|
||||
};
|
||||
|
||||
_mainFormText.Add(control.Name, new[] {"Add [{0}] Server", fullName});
|
||||
control.Click += AddServerToolStripMenuItem_Click;
|
||||
ServerToolStripMenuItem.DropDownItems.Add(control);
|
||||
@@ -174,20 +176,24 @@ namespace Netch.Forms
|
||||
case Control c:
|
||||
if (_mainFormText.ContainsKey(c.Name))
|
||||
c.Text = ControlText(c.Name);
|
||||
|
||||
break;
|
||||
case ToolStripItem c:
|
||||
if (_mainFormText.ContainsKey(c.Name))
|
||||
c.Text = ControlText(c.Name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
string ControlText(string name)
|
||||
{
|
||||
var value = _mainFormText[name];
|
||||
if (value.Equals(string.Empty)) return string.Empty;
|
||||
if (value.Equals(string.Empty))
|
||||
return string.Empty;
|
||||
|
||||
if (value is object[] values)
|
||||
return i18N.TranslateFormat(values.First() as string, values.Skip(1).ToArray());
|
||||
|
||||
return i18N.Translate(value);
|
||||
}
|
||||
}
|
||||
@@ -325,6 +331,7 @@ namespace Netch.Forms
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
|
||||
}
|
||||
@@ -438,6 +445,7 @@ namespace Netch.Forms
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
|
||||
await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
|
||||
}
|
||||
|
||||
@@ -686,8 +694,7 @@ namespace Netch.Forms
|
||||
public void SelectLastServer()
|
||||
{
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ServerComboBoxSelectedIndex > 0 &&
|
||||
Global.Settings.ServerComboBoxSelectedIndex < ServerComboBox.Items.Count)
|
||||
if (Global.Settings.ServerComboBoxSelectedIndex > 0 && Global.Settings.ServerComboBoxSelectedIndex < ServerComboBox.Items.Count)
|
||||
ServerComboBox.SelectedIndex = Global.Settings.ServerComboBoxSelectedIndex;
|
||||
// 如果值非法,且当前 ServerComboBox 中有元素,选择第一个位置
|
||||
else if (ServerComboBox.Items.Count > 0)
|
||||
@@ -698,7 +705,9 @@ namespace Netch.Forms
|
||||
|
||||
private void ServerComboBox_SelectedIndexChanged(object sender, EventArgs o)
|
||||
{
|
||||
if (!_comboBoxInitialized) return;
|
||||
if (!_comboBoxInitialized)
|
||||
return;
|
||||
|
||||
Global.Settings.ServerComboBoxSelectedIndex = ServerComboBox.SelectedIndex;
|
||||
}
|
||||
|
||||
@@ -806,8 +815,7 @@ namespace Netch.Forms
|
||||
public void SelectLastMode()
|
||||
{
|
||||
// 如果值合法,选中该位置
|
||||
if (Global.Settings.ModeComboBoxSelectedIndex > 0 &&
|
||||
Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
|
||||
if (Global.Settings.ModeComboBoxSelectedIndex > 0 && Global.Settings.ModeComboBoxSelectedIndex < ModeComboBox.Items.Count)
|
||||
ModeComboBox.SelectedIndex = Global.Settings.ModeComboBoxSelectedIndex;
|
||||
// 如果值非法,且当前 ModeComboBox 中有元素,选择第一个位置
|
||||
else if (ModeComboBox.Items.Count > 0)
|
||||
@@ -818,7 +826,9 @@ namespace Netch.Forms
|
||||
|
||||
private void ModeComboBox_SelectedIndexChanged(object sender, EventArgs o)
|
||||
{
|
||||
if (!_comboBoxInitialized) return;
|
||||
if (!_comboBoxInitialized)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Global.Settings.ModeComboBoxSelectedIndex = Global.Modes.IndexOf((Models.Mode) ModeComboBox.SelectedItem);
|
||||
@@ -906,6 +916,7 @@ namespace Netch.Forms
|
||||
|
||||
if (Global.Settings.ProfileTableColumnCount == 0)
|
||||
Global.Settings.ProfileTableColumnCount = 5;
|
||||
|
||||
var columnCount = Global.Settings.ProfileTableColumnCount;
|
||||
|
||||
ProfileTable.ColumnCount = profileCount >= columnCount ? columnCount : profileCount;
|
||||
@@ -966,6 +977,7 @@ namespace Netch.Forms
|
||||
Profile profile;
|
||||
if ((profile = Global.Settings.Profiles.SingleOrDefault(p => p.Index == index)) != null)
|
||||
Global.Settings.Profiles.Remove(profile);
|
||||
|
||||
profile = new Profile(server, mode, name, index);
|
||||
Global.Settings.Profiles.Add(profile);
|
||||
return profile;
|
||||
@@ -1006,6 +1018,7 @@ namespace Netch.Forms
|
||||
case Keys.Shift:
|
||||
if (profile == null)
|
||||
return;
|
||||
|
||||
Global.Settings.Profiles.Remove(profile);
|
||||
profileButton.Tag = null;
|
||||
profileButton.Text = i18N.Translate("None");
|
||||
@@ -1055,22 +1068,14 @@ namespace Netch.Forms
|
||||
{
|
||||
void StartDisableItems(bool enabled)
|
||||
{
|
||||
ServerComboBox.Enabled =
|
||||
ModeComboBox.Enabled =
|
||||
EditModePictureBox.Enabled =
|
||||
EditServerPictureBox.Enabled =
|
||||
DeleteModePictureBox.Enabled =
|
||||
DeleteServerPictureBox.Enabled = enabled;
|
||||
ServerComboBox.Enabled = ModeComboBox.Enabled = EditModePictureBox.Enabled =
|
||||
EditServerPictureBox.Enabled = DeleteModePictureBox.Enabled = DeleteServerPictureBox.Enabled = enabled;
|
||||
|
||||
// 启动需要禁用的控件
|
||||
UninstallServiceToolStripMenuItem.Enabled =
|
||||
UpdateACLToolStripMenuItem.Enabled =
|
||||
updateACLWithProxyToolStripMenuItem.Enabled =
|
||||
updatePACToolStripMenuItem.Enabled =
|
||||
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
|
||||
UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Enabled =
|
||||
UninstallTapDriverToolStripMenuItem.Enabled =
|
||||
ReloadModesToolStripMenuItem.Enabled = enabled;
|
||||
UninstallServiceToolStripMenuItem.Enabled = UpdateACLToolStripMenuItem.Enabled = updateACLWithProxyToolStripMenuItem.Enabled =
|
||||
updatePACToolStripMenuItem.Enabled = UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled =
|
||||
UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem.Enabled = UninstallTapDriverToolStripMenuItem.Enabled =
|
||||
ReloadModesToolStripMenuItem.Enabled = enabled;
|
||||
}
|
||||
|
||||
_state = value;
|
||||
@@ -1126,6 +1131,7 @@ namespace Netch.Forms
|
||||
{
|
||||
return State == State.Waiting || State == State.Stopped;
|
||||
}
|
||||
|
||||
private static bool IsWaiting(State state)
|
||||
{
|
||||
return state == State.Waiting || state == State.Stopped;
|
||||
@@ -1159,6 +1165,7 @@ namespace Netch.Forms
|
||||
|
||||
if (IsWaiting())
|
||||
return;
|
||||
|
||||
UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = state;
|
||||
}
|
||||
|
||||
@@ -1243,6 +1250,7 @@ namespace Netch.Forms
|
||||
{
|
||||
if (!MainController.Mode.TestNatRequired())
|
||||
return;
|
||||
|
||||
NttTested = false;
|
||||
Task.Run(() =>
|
||||
{
|
||||
@@ -1285,6 +1293,7 @@ namespace Netch.Forms
|
||||
Logging.Info("操作系统即将挂起,自动停止");
|
||||
ControlButton_Click(null, null);
|
||||
}
|
||||
|
||||
break;
|
||||
case PowerModes.Resume: //操作系统即将从挂起状态继续
|
||||
if (_resumeFlag)
|
||||
@@ -1293,6 +1302,7 @@ namespace Netch.Forms
|
||||
Logging.Info("操作系统即将从挂起状态继续,自动重启");
|
||||
ControlButton_Click(null, null);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1358,6 +1368,7 @@ namespace Netch.Forms
|
||||
#region FormClosingButton
|
||||
|
||||
private bool _isFirstCloseWindow = true;
|
||||
|
||||
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing && State != State.Terminating)
|
||||
@@ -1385,6 +1396,7 @@ namespace Netch.Forms
|
||||
NotifyTip($"{i18N.Translate(@"New version available", ": ")}{UpdateChecker.LatestVersionNumber}");
|
||||
NewVersionLabel.Visible = true;
|
||||
};
|
||||
|
||||
UpdateChecker.Check(Global.Settings.CheckBetaUpdate);
|
||||
}
|
||||
|
||||
@@ -1398,6 +1410,7 @@ namespace Netch.Forms
|
||||
|
||||
if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
NotifyTip(i18N.Translate("Start downloading new version"));
|
||||
|
||||
NewVersionLabel.Enabled = false;
|
||||
@@ -1495,10 +1508,7 @@ namespace Netch.Forms
|
||||
public void NotifyTip(string text, int timeout = 0, bool info = true)
|
||||
{
|
||||
// 会阻塞线程 timeout 秒
|
||||
NotifyIcon.ShowBalloonTip(timeout,
|
||||
UpdateChecker.Name,
|
||||
text,
|
||||
info ? ToolTipIcon.Info : ToolTipIcon.Error);
|
||||
NotifyIcon.ShowBalloonTip(timeout, UpdateChecker.Name, text, info ? ToolTipIcon.Info : ToolTipIcon.Error);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1518,7 +1528,8 @@ namespace Netch.Forms
|
||||
// 绘制背景颜色
|
||||
e.Graphics.FillRectangle(Brushes.White, e.Bounds);
|
||||
|
||||
if (e.Index < 0) return;
|
||||
if (e.Index < 0)
|
||||
return;
|
||||
|
||||
// 绘制 备注/名称 字符串
|
||||
TextRenderer.DrawText(e.Graphics, cbx.Items[e.Index].ToString(), cbx.Font, e.Bounds, Color.Black, TextFormatFlags.Left);
|
||||
@@ -1528,29 +1539,34 @@ namespace Netch.Forms
|
||||
case Server item:
|
||||
{
|
||||
// 计算延迟底色
|
||||
var numBoxBackBrush = item.Delay switch
|
||||
{
|
||||
> 200 => Brushes.Red,
|
||||
> 80 => Brushes.Yellow,
|
||||
>= 0 => _greenBrush,
|
||||
_ => Brushes.Gray
|
||||
};
|
||||
var numBoxBackBrush = item.Delay switch {> 200 => Brushes.Red, > 80 => Brushes.Yellow, >= 0 => _greenBrush, _ => Brushes.Gray};
|
||||
|
||||
// 绘制延迟底色
|
||||
e.Graphics.FillRectangle(numBoxBackBrush, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
|
||||
|
||||
// 绘制延迟字符串
|
||||
TextRenderer.DrawText(e.Graphics, item.Delay.ToString(), cbx.Font, new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y), Color.Black, TextFormatFlags.Left);
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Delay.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
TextFormatFlags.Left);
|
||||
|
||||
break;
|
||||
}
|
||||
case Models.Mode item:
|
||||
{
|
||||
// 绘制 模式Box 底色
|
||||
e.Graphics.FillRectangle(Brushes.Gray, _numberBoxX, e.Bounds.Y, _numberBoxWidth,
|
||||
e.Bounds.Height);
|
||||
e.Graphics.FillRectangle(Brushes.Gray, _numberBoxX, e.Bounds.Y, _numberBoxWidth, e.Bounds.Height);
|
||||
|
||||
// 绘制 模式行数 字符串
|
||||
TextRenderer.DrawText(e.Graphics, item.Rule.Count.ToString(), cbx.Font, new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y), Color.Black, TextFormatFlags.Left);
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
item.Rule.Count.ToString(),
|
||||
cbx.Font,
|
||||
new Point(_numberBoxX + _numberBoxWrap, e.Bounds.Y),
|
||||
Color.Black,
|
||||
TextFormatFlags.Left);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,32 +14,31 @@ namespace Netch.Forms
|
||||
/// <param name="level">弹窗等级 (标题, 图标)</param>
|
||||
/// <param name="confirm">需要确认</param>
|
||||
/// <param name="owner">阻止 owner Focus() 直到 Messageox 被关闭</param>
|
||||
public static DialogResult Show(string text, LogLevel level = LogLevel.INFO, string title = "", bool confirm = false, IWin32Window owner = null)
|
||||
public static DialogResult Show(string text,
|
||||
LogLevel level = LogLevel.INFO,
|
||||
string title = "",
|
||||
bool confirm = false,
|
||||
IWin32Window owner = null)
|
||||
{
|
||||
MessageBoxIcon msgIcon;
|
||||
if (string.IsNullOrWhiteSpace(title))
|
||||
title = level switch
|
||||
{
|
||||
LogLevel.INFO => "Information",
|
||||
LogLevel.WARNING => "Warning",
|
||||
LogLevel.ERROR => "Error",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
{
|
||||
LogLevel.INFO => "Information",
|
||||
LogLevel.WARNING => "Warning",
|
||||
LogLevel.ERROR => "Error",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
|
||||
msgIcon = level switch
|
||||
{
|
||||
LogLevel.INFO => MessageBoxIcon.Information,
|
||||
LogLevel.WARNING => MessageBoxIcon.Warning,
|
||||
LogLevel.ERROR => MessageBoxIcon.Exclamation,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
{
|
||||
LogLevel.INFO => MessageBoxIcon.Information,
|
||||
LogLevel.WARNING => MessageBoxIcon.Warning,
|
||||
LogLevel.ERROR => MessageBoxIcon.Exclamation,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
|
||||
return MessageBox.Show(
|
||||
owner,
|
||||
text,
|
||||
i18N.Translate(title),
|
||||
confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK,
|
||||
msgIcon);
|
||||
return MessageBox.Show(owner, text, i18N.Translate(title), confirm ? MessageBoxButtons.OKCancel : MessageBoxButtons.OK, msgIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,8 +36,7 @@ namespace Netch.Forms.Mode
|
||||
#region 禁用文件名更改
|
||||
|
||||
RemarkTextBox.TextChanged -= RemarkTextBox_TextChanged;
|
||||
FilenameTextBox.Enabled =
|
||||
UseCustomFilenameBox.Enabled = false;
|
||||
FilenameTextBox.Enabled = UseCustomFilenameBox.Enabled = false;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -66,7 +65,9 @@ namespace Netch.Forms.Mode
|
||||
{
|
||||
try
|
||||
{
|
||||
RuleListBox.Items.AddRange(Directory.GetFiles(DirName, "*.exe", SearchOption.AllDirectories).Select(f => Path.GetFileName(f)).ToArray());
|
||||
RuleListBox.Items.AddRange(Directory.GetFiles(DirName, "*.exe", SearchOption.AllDirectories)
|
||||
.Select(f => Path.GetFileName(f))
|
||||
.ToArray());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -88,13 +89,16 @@ namespace Netch.Forms.Mode
|
||||
RuleListBox.SelectedIndex = RuleListBox.IndexFromPoint(e.X, e.Y);
|
||||
if (RuleListBox.SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
if (e.Button == MouseButtons.Right)
|
||||
contextMenuStrip.Show(RuleListBox, e.Location);
|
||||
}
|
||||
|
||||
private void deleteRule_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (RuleListBox.SelectedIndex == -1) return;
|
||||
if (RuleListBox.SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
RuleListBox.Items.RemoveAt(RuleListBox.SelectedIndex);
|
||||
Edited = true;
|
||||
}
|
||||
@@ -137,6 +141,7 @@ namespace Netch.Forms.Mode
|
||||
EnsurePathExists = true,
|
||||
NavigateToShortcut = true
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog(Win32Native.GetForegroundWindow()) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
ScanDirectory(dialog.FileName);
|
||||
@@ -191,6 +196,7 @@ namespace Netch.Forms.Mode
|
||||
Type = 0,
|
||||
Remark = RemarkTextBox.Text
|
||||
};
|
||||
|
||||
mode.Rule.AddRange(RuleListBox.Items.Cast<string>());
|
||||
|
||||
mode.WriteFile();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
@@ -10,18 +10,28 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
|
||||
[DesignerCategory(@"Code")]
|
||||
public abstract class ServerForm : Form
|
||||
{
|
||||
protected abstract string TypeName { get; }
|
||||
protected Server Server { get; set; }
|
||||
|
||||
private int _controlLines = 2;
|
||||
|
||||
private const int ControlLineHeight = 28;
|
||||
private const int InputBoxWidth = 294;
|
||||
|
||||
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new();
|
||||
|
||||
private readonly Dictionary<Control, Action<object>> _saveActions = new();
|
||||
|
||||
private int _controlLines = 2;
|
||||
private Label AddressLabel;
|
||||
protected TextBox AddressTextBox;
|
||||
|
||||
private readonly IContainer components = null;
|
||||
|
||||
private GroupBox ConfigurationGroupBox;
|
||||
private Label PortLabel;
|
||||
private TextBox PortTextBox;
|
||||
private Label RemarkLabel;
|
||||
protected TextBox RemarkTextBox;
|
||||
|
||||
protected ServerForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -36,6 +46,10 @@ namespace Netch.Forms
|
||||
_saveActions.Add(PortTextBox, s => Server.Port = ushort.Parse((string) s));
|
||||
}
|
||||
|
||||
protected abstract string TypeName { get; }
|
||||
|
||||
protected Server Server { get; set; }
|
||||
|
||||
public new void ShowDialog()
|
||||
{
|
||||
AfterFactor();
|
||||
@@ -65,7 +79,12 @@ namespace Netch.Forms
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
protected void CreateTextBox(string name, string remark, Func<string, bool> check, Action<string> save, string value, int width = InputBoxWidth)
|
||||
protected void CreateTextBox(string name,
|
||||
string remark,
|
||||
Func<string, bool> check,
|
||||
Action<string> save,
|
||||
string value,
|
||||
int width = InputBoxWidth)
|
||||
{
|
||||
_controlLines++;
|
||||
|
||||
@@ -77,22 +96,21 @@ namespace Netch.Forms
|
||||
TextAlign = HorizontalAlignment.Center,
|
||||
Text = value
|
||||
};
|
||||
|
||||
_checkActions.Add(textBox, check);
|
||||
_saveActions.Add(textBox, o => save.Invoke((string) o));
|
||||
ConfigurationGroupBox.Controls.AddRange(
|
||||
new Control[]
|
||||
ConfigurationGroupBox.Controls.AddRange(new Control[]
|
||||
{
|
||||
textBox,
|
||||
new Label
|
||||
{
|
||||
textBox,
|
||||
new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
Location = new Point(10, ControlLineHeight * _controlLines),
|
||||
Name = $"{name}Label",
|
||||
Size = new Size(56, 17),
|
||||
Text = remark
|
||||
}
|
||||
AutoSize = true,
|
||||
Location = new Point(10, ControlLineHeight * _controlLines),
|
||||
Name = $"{name}Label",
|
||||
Size = new Size(56, 17),
|
||||
Text = remark
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected void CreateComboBox(string name, string remark, List<string> values, Action<string> save, string value, int width = InputBoxWidth)
|
||||
@@ -108,24 +126,23 @@ namespace Netch.Forms
|
||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||
FormattingEnabled = true
|
||||
};
|
||||
|
||||
comboBox.Items.AddRange(values.ToArray());
|
||||
comboBox.SelectedIndex = values.IndexOf(value);
|
||||
comboBox.DrawItem += Utils.Utils.DrawCenterComboBox;
|
||||
_saveActions.Add(comboBox, o => save.Invoke((string) o));
|
||||
ConfigurationGroupBox.Controls.AddRange(
|
||||
new Control[]
|
||||
ConfigurationGroupBox.Controls.AddRange(new Control[]
|
||||
{
|
||||
comboBox,
|
||||
new Label
|
||||
{
|
||||
comboBox,
|
||||
new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
Location = new Point(10, ControlLineHeight * _controlLines),
|
||||
Name = $"{name}Label",
|
||||
Size = new Size(56, 17),
|
||||
Text = remark
|
||||
}
|
||||
AutoSize = true,
|
||||
Location = new Point(10, ControlLineHeight * _controlLines),
|
||||
Name = $"{name}Label",
|
||||
Size = new Size(56, 17),
|
||||
Text = remark
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected void CreateCheckBox(string name, string remark, Action<bool> save, bool value)
|
||||
@@ -140,19 +157,14 @@ namespace Netch.Forms
|
||||
Checked = value,
|
||||
Text = remark
|
||||
};
|
||||
|
||||
_saveActions.Add(checkBox, o => save.Invoke((bool) o));
|
||||
ConfigurationGroupBox.Controls.AddRange(
|
||||
new Control[]
|
||||
{
|
||||
checkBox
|
||||
}
|
||||
);
|
||||
ConfigurationGroupBox.Controls.AddRange(new Control[]
|
||||
{
|
||||
checkBox
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new Dictionary<Control, Func<string, bool>>();
|
||||
|
||||
private readonly Dictionary<Control, Action<object>> _saveActions = new Dictionary<Control, Action<object>>();
|
||||
|
||||
private void AddSaveButton()
|
||||
{
|
||||
_controlLines++;
|
||||
@@ -164,6 +176,7 @@ namespace Netch.Forms
|
||||
Text = "Save",
|
||||
UseVisualStyleBackColor = true
|
||||
};
|
||||
|
||||
control.Click += ControlButton_Click;
|
||||
ConfigurationGroupBox.Controls.Add(control);
|
||||
}
|
||||
@@ -180,12 +193,9 @@ namespace Netch.Forms
|
||||
}
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var pair in _saveActions)
|
||||
{
|
||||
switch (pair.Key)
|
||||
{
|
||||
case CheckBox c:
|
||||
@@ -195,7 +205,6 @@ namespace Netch.Forms
|
||||
pair.Value.Invoke(pair.Key.Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.Settings.Server.IndexOf(Server) == -1)
|
||||
Global.Settings.Server.Add(Server);
|
||||
@@ -205,14 +214,10 @@ namespace Netch.Forms
|
||||
Close();
|
||||
}
|
||||
|
||||
private IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
components?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
@@ -306,7 +311,7 @@ namespace Netch.Forms
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||
ClientSize = new Size(444, 137);
|
||||
Controls.Add(ConfigurationGroupBox);
|
||||
Font = new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, (byte) 134);
|
||||
Font = new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
|
||||
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||
Icon = Icon.FromHandle(Resources.Netch.GetHicon());
|
||||
Margin = new Padding(3, 4, 3, 4);
|
||||
@@ -315,13 +320,5 @@ namespace Netch.Forms
|
||||
Padding = new Padding(11, 5, 11, 4);
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
}
|
||||
|
||||
private GroupBox ConfigurationGroupBox;
|
||||
private Label RemarkLabel;
|
||||
protected TextBox RemarkTextBox;
|
||||
private Label PortLabel;
|
||||
protected TextBox AddressTextBox;
|
||||
private TextBox PortTextBox;
|
||||
private Label AddressLabel;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace Netch.Forms
|
||||
private readonly Dictionary<Control, Func<string, bool>> _checkActions = new();
|
||||
|
||||
private readonly Dictionary<Control, Action<Control>> _saveActions = new();
|
||||
|
||||
public SettingForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -36,46 +37,34 @@ namespace Netch.Forms
|
||||
p => p.ToString() != HTTPPortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
|
||||
p => Global.Settings.Socks5LocalPort = p,
|
||||
Global.Settings.Socks5LocalPort);
|
||||
|
||||
BindTextBox<ushort>(HTTPPortTextBox,
|
||||
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != RedirectorTextBox.Text,
|
||||
p => Global.Settings.HTTPLocalPort = p,
|
||||
Global.Settings.HTTPLocalPort);
|
||||
|
||||
BindTextBox<ushort>(RedirectorTextBox,
|
||||
p => p.ToString() != Socks5PortTextBox.Text && p.ToString() != HTTPPortTextBox.Text,
|
||||
p => Global.Settings.RedirectorTCPPort = p,
|
||||
Global.Settings.RedirectorTCPPort);
|
||||
|
||||
BindCheckBox(AllowDevicesCheckBox,
|
||||
c => Global.Settings.LocalAddress = AllowDevicesCheckBox.Checked ? "0.0.0.0" : "127.0.0.1",
|
||||
Global.Settings.LocalAddress switch
|
||||
{
|
||||
"127.0.0.1" => false,
|
||||
"0.0.0.0" => true,
|
||||
_ => false
|
||||
});
|
||||
Global.Settings.LocalAddress switch {"127.0.0.1" => false, "0.0.0.0" => true, _ => false});
|
||||
|
||||
BindCheckBox(BootShadowsocksFromDLLCheckBox,
|
||||
c => Global.Settings.BootShadowsocksFromDLL = c,
|
||||
Global.Settings.BootShadowsocksFromDLL);
|
||||
BindCheckBox(ResolveServerHostnameCheckBox,
|
||||
c => Global.Settings.ResolveServerHostname = c,
|
||||
Global.Settings.ResolveServerHostname);
|
||||
BindCheckBox(BootShadowsocksFromDLLCheckBox, c => Global.Settings.BootShadowsocksFromDLL = c, Global.Settings.BootShadowsocksFromDLL);
|
||||
BindCheckBox(ResolveServerHostnameCheckBox, c => Global.Settings.ResolveServerHostname = c, Global.Settings.ResolveServerHostname);
|
||||
|
||||
BindRadioBox(ICMPingRadioBtn,
|
||||
_ => { },
|
||||
!Global.Settings.ServerTCPing);
|
||||
BindRadioBox(ICMPingRadioBtn, _ => { }, !Global.Settings.ServerTCPing);
|
||||
|
||||
BindRadioBox(TCPingRadioBtn,
|
||||
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,
|
||||
Global.Settings.ProfileCount);
|
||||
BindTextBox<int>(ProfileCountTextBox, i => i > -1, i => Global.Settings.ProfileCount = i, Global.Settings.ProfileCount);
|
||||
BindTextBox<int>(DetectionTickTextBox,
|
||||
i => ServerHelper.DelayTestHelper.Range.InRange(i),
|
||||
i => Global.Settings.DetectionTick = i,
|
||||
Global.Settings.DetectionTick);
|
||||
|
||||
BindTextBox<int>(StartedPingIntervalTextBox,
|
||||
_ => true,
|
||||
i => Global.Settings.StartedPingInterval = i,
|
||||
@@ -83,10 +72,7 @@ namespace Netch.Forms
|
||||
|
||||
InitSTUN();
|
||||
|
||||
BindTextBox<string>(AclAddrTextBox,
|
||||
s => true,
|
||||
s => Global.Settings.ACL = s,
|
||||
Global.Settings.ACL);
|
||||
BindTextBox<string>(AclAddrTextBox, s => true, s => Global.Settings.ACL = s, Global.Settings.ACL);
|
||||
AclAddrTextBox.Text = Global.Settings.ACL;
|
||||
|
||||
LanguageComboBox.Items.AddRange(i18N.GetTranslateList().ToArray());
|
||||
@@ -96,26 +82,15 @@ namespace Netch.Forms
|
||||
|
||||
#region Process Mode
|
||||
|
||||
BindCheckBox(ModifySystemDNSCheckBox,
|
||||
b => Global.Settings.ModifySystemDNS = b,
|
||||
Global.Settings.ModifySystemDNS);
|
||||
BindCheckBox(ModifySystemDNSCheckBox, b => Global.Settings.ModifySystemDNS = b, Global.Settings.ModifySystemDNS);
|
||||
|
||||
BindTextBox(ModifiedDNSTextBox,
|
||||
s => DNS.TrySplit(s, out _, 2),
|
||||
s => Global.Settings.ModifiedDNS = s,
|
||||
Global.Settings.ModifiedDNS);
|
||||
BindTextBox(ModifiedDNSTextBox, s => DNS.TrySplit(s, out _, 2), s => Global.Settings.ModifiedDNS = s, Global.Settings.ModifiedDNS);
|
||||
|
||||
BindCheckBox(RedirectorSSCheckBox,
|
||||
s => Global.Settings.RedirectorSS = s,
|
||||
Global.Settings.RedirectorSS);
|
||||
BindCheckBox(RedirectorSSCheckBox, s => Global.Settings.RedirectorSS = s, Global.Settings.RedirectorSS);
|
||||
|
||||
BindCheckBox(NoProxyForUdpCheckBox,
|
||||
s => Global.Settings.ProcessNoProxyForUdp = s,
|
||||
Global.Settings.ProcessNoProxyForUdp);
|
||||
BindCheckBox(NoProxyForUdpCheckBox, s => Global.Settings.ProcessNoProxyForUdp = s, Global.Settings.ProcessNoProxyForUdp);
|
||||
|
||||
BindCheckBox(NoProxyForTcpCheckBox,
|
||||
s => Global.Settings.ProcessNoProxyForTcp = s,
|
||||
Global.Settings.ProcessNoProxyForTcp);
|
||||
BindCheckBox(NoProxyForTcpCheckBox, s => Global.Settings.ProcessNoProxyForTcp = s, Global.Settings.ProcessNoProxyForTcp);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -125,17 +100,18 @@ namespace Netch.Forms
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.TUNTAP.Address = s,
|
||||
Global.Settings.TUNTAP.Address);
|
||||
|
||||
BindTextBox(TUNTAPNetmaskTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.TUNTAP.Netmask = s,
|
||||
Global.Settings.TUNTAP.Netmask);
|
||||
|
||||
BindTextBox(TUNTAPGatewayTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
s => Global.Settings.TUNTAP.Gateway = s,
|
||||
Global.Settings.TUNTAP.Gateway);
|
||||
BindCheckBox(UseCustomDNSCheckBox,
|
||||
b => { Global.Settings.TUNTAP.UseCustomDNS = b; },
|
||||
Global.Settings.TUNTAP.UseCustomDNS);
|
||||
|
||||
BindCheckBox(UseCustomDNSCheckBox, b => { Global.Settings.TUNTAP.UseCustomDNS = b; }, Global.Settings.TUNTAP.UseCustomDNS);
|
||||
|
||||
BindTextBox(TUNTAPDNSTextBox,
|
||||
s => !UseCustomDNSCheckBox.Checked || DNS.TrySplit(s, out _, 2),
|
||||
@@ -146,52 +122,40 @@ namespace Netch.Forms
|
||||
},
|
||||
DNS.Join(Global.Settings.TUNTAP.DNS));
|
||||
|
||||
BindCheckBox(ProxyDNSCheckBox,
|
||||
b => Global.Settings.TUNTAP.ProxyDNS = b,
|
||||
Global.Settings.TUNTAP.ProxyDNS);
|
||||
BindCheckBox(UseFakeDNSCheckBox,
|
||||
b => Global.Settings.TUNTAP.UseFakeDNS = b,
|
||||
Global.Settings.TUNTAP.UseFakeDNS);
|
||||
BindCheckBox(ProxyDNSCheckBox, b => Global.Settings.TUNTAP.ProxyDNS = b, Global.Settings.TUNTAP.ProxyDNS);
|
||||
BindCheckBox(UseFakeDNSCheckBox, b => Global.Settings.TUNTAP.UseFakeDNS = b, Global.Settings.TUNTAP.UseFakeDNS);
|
||||
|
||||
#endregion
|
||||
|
||||
#region V2Ray
|
||||
|
||||
BindCheckBox(XrayConeCheckBox,
|
||||
b => Global.Settings.V2RayConfig.XrayCone = b,
|
||||
Global.Settings.V2RayConfig.XrayCone);
|
||||
BindCheckBox(XrayConeCheckBox, b => Global.Settings.V2RayConfig.XrayCone = b, Global.Settings.V2RayConfig.XrayCone);
|
||||
|
||||
BindCheckBox(TLSAllowInsecureCheckBox,
|
||||
b => Global.Settings.V2RayConfig.AllowInsecure = b,
|
||||
Global.Settings.V2RayConfig.AllowInsecure);
|
||||
BindCheckBox(UseMuxCheckBox,
|
||||
b => Global.Settings.V2RayConfig.UseMux = b,
|
||||
Global.Settings.V2RayConfig.UseMux);
|
||||
BindCheckBox(TLSAllowInsecureCheckBox, b => Global.Settings.V2RayConfig.AllowInsecure = b, Global.Settings.V2RayConfig.AllowInsecure);
|
||||
BindCheckBox(UseMuxCheckBox, b => Global.Settings.V2RayConfig.UseMux = b, Global.Settings.V2RayConfig.UseMux);
|
||||
|
||||
BindTextBox<int>(mtuTextBox,
|
||||
i => true,
|
||||
i => Global.Settings.V2RayConfig.KcpConfig.mtu = i,
|
||||
Global.Settings.V2RayConfig.KcpConfig.mtu);
|
||||
BindTextBox<int>(ttiTextBox,
|
||||
i => true,
|
||||
i => Global.Settings.V2RayConfig.KcpConfig.tti = i,
|
||||
Global.Settings.V2RayConfig.KcpConfig.tti);
|
||||
BindTextBox<int>(mtuTextBox, i => true, i => Global.Settings.V2RayConfig.KcpConfig.mtu = i, Global.Settings.V2RayConfig.KcpConfig.mtu);
|
||||
BindTextBox<int>(ttiTextBox, i => true, i => Global.Settings.V2RayConfig.KcpConfig.tti = i, Global.Settings.V2RayConfig.KcpConfig.tti);
|
||||
BindTextBox<int>(uplinkCapacityTextBox,
|
||||
i => true,
|
||||
i => Global.Settings.V2RayConfig.KcpConfig.uplinkCapacity = i,
|
||||
Global.Settings.V2RayConfig.KcpConfig.uplinkCapacity);
|
||||
|
||||
BindTextBox<int>(downlinkCapacityTextBox,
|
||||
i => true,
|
||||
i => Global.Settings.V2RayConfig.KcpConfig.downlinkCapacity = i,
|
||||
Global.Settings.V2RayConfig.KcpConfig.downlinkCapacity);
|
||||
|
||||
BindTextBox<int>(readBufferSizeTextBox,
|
||||
i => true,
|
||||
i => Global.Settings.V2RayConfig.KcpConfig.readBufferSize = i,
|
||||
Global.Settings.V2RayConfig.KcpConfig.readBufferSize);
|
||||
|
||||
BindTextBox<int>(writeBufferSizeTextBox,
|
||||
i => true,
|
||||
i => Global.Settings.V2RayConfig.KcpConfig.writeBufferSize = i,
|
||||
Global.Settings.V2RayConfig.KcpConfig.writeBufferSize);
|
||||
|
||||
BindCheckBox(congestionCheckBox,
|
||||
b => Global.Settings.V2RayConfig.KcpConfig.congestion = b,
|
||||
Global.Settings.V2RayConfig.KcpConfig.congestion);
|
||||
@@ -200,46 +164,27 @@ namespace Netch.Forms
|
||||
|
||||
#region Others
|
||||
|
||||
BindCheckBox(ExitWhenClosedCheckBox,
|
||||
b => Global.Settings.ExitWhenClosed = b,
|
||||
Global.Settings.ExitWhenClosed);
|
||||
BindCheckBox(ExitWhenClosedCheckBox, b => Global.Settings.ExitWhenClosed = b, Global.Settings.ExitWhenClosed);
|
||||
|
||||
BindCheckBox(StopWhenExitedCheckBox,
|
||||
b => Global.Settings.StopWhenExited = b,
|
||||
Global.Settings.StopWhenExited);
|
||||
BindCheckBox(StopWhenExitedCheckBox, b => Global.Settings.StopWhenExited = b, Global.Settings.StopWhenExited);
|
||||
|
||||
BindCheckBox(StartWhenOpenedCheckBox,
|
||||
b => Global.Settings.StartWhenOpened = b,
|
||||
Global.Settings.StartWhenOpened);
|
||||
BindCheckBox(StartWhenOpenedCheckBox, b => Global.Settings.StartWhenOpened = b, Global.Settings.StartWhenOpened);
|
||||
|
||||
BindCheckBox(MinimizeWhenStartedCheckBox,
|
||||
b => Global.Settings.MinimizeWhenStarted = b,
|
||||
Global.Settings.MinimizeWhenStarted);
|
||||
BindCheckBox(MinimizeWhenStartedCheckBox, b => Global.Settings.MinimizeWhenStarted = b, Global.Settings.MinimizeWhenStarted);
|
||||
|
||||
BindCheckBox(RunAtStartupCheckBox,
|
||||
b => Global.Settings.RunAtStartup = b,
|
||||
Global.Settings.RunAtStartup);
|
||||
BindCheckBox(RunAtStartupCheckBox, b => Global.Settings.RunAtStartup = b, Global.Settings.RunAtStartup);
|
||||
|
||||
BindCheckBox(CheckUpdateWhenOpenedCheckBox,
|
||||
b => Global.Settings.CheckUpdateWhenOpened = b,
|
||||
Global.Settings.CheckUpdateWhenOpened);
|
||||
BindCheckBox(CheckUpdateWhenOpenedCheckBox, b => Global.Settings.CheckUpdateWhenOpened = b, Global.Settings.CheckUpdateWhenOpened);
|
||||
|
||||
BindCheckBox(CheckBetaUpdateCheckBox,
|
||||
b => Global.Settings.CheckBetaUpdate = b,
|
||||
Global.Settings.CheckBetaUpdate);
|
||||
BindCheckBox(CheckBetaUpdateCheckBox, b => Global.Settings.CheckBetaUpdate = b, Global.Settings.CheckBetaUpdate);
|
||||
|
||||
BindCheckBox(UpdateServersWhenOpenedCheckBox,
|
||||
b => Global.Settings.UpdateServersWhenOpened = b,
|
||||
Global.Settings.UpdateServersWhenOpened);
|
||||
BindCheckBox(UpdateServersWhenOpenedCheckBox, b => Global.Settings.UpdateServersWhenOpened = b, Global.Settings.UpdateServersWhenOpened);
|
||||
|
||||
#endregion
|
||||
|
||||
#region AioDNS
|
||||
|
||||
BindTextBox(AioDNSRulePathTextBox,
|
||||
s => true,
|
||||
s => Global.Settings.AioDNS.RulePath = s,
|
||||
Global.Settings.AioDNS.RulePath);
|
||||
BindTextBox(AioDNSRulePathTextBox, s => true, s => Global.Settings.AioDNS.RulePath = s, Global.Settings.AioDNS.RulePath);
|
||||
|
||||
BindTextBox(ChinaDNSTextBox,
|
||||
s => IPAddress.TryParse(s, out _),
|
||||
@@ -257,9 +202,7 @@ namespace Netch.Forms
|
||||
private void TUNTAPUseCustomDNSCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (UseCustomDNSCheckBox.Checked)
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
|
||||
? DNS.Join(Global.Settings.TUNTAP.DNS)
|
||||
: "1.1.1.1";
|
||||
TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any() ? DNS.Join(Global.Settings.TUNTAP.DNS) : "1.1.1.1";
|
||||
else
|
||||
TUNTAPDNSTextBox.Text = "AioDNS";
|
||||
}
|
||||
@@ -358,17 +301,19 @@ namespace Netch.Forms
|
||||
private void BindTextBox<T>(TextBox control, Func<T, bool> check, Action<T> save, object value)
|
||||
{
|
||||
control.Text = value.ToString();
|
||||
_checkActions.Add(control, s =>
|
||||
{
|
||||
try
|
||||
_checkActions.Add(control,
|
||||
s =>
|
||||
{
|
||||
return check.Invoke((T) Convert.ChangeType(s, typeof(T)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
return check.Invoke((T) Convert.ChangeType(s, typeof(T)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
_saveActions.Add(control, c => save.Invoke((T) Convert.ChangeType(((TextBox) c).Text, typeof(T))));
|
||||
}
|
||||
|
||||
@@ -377,6 +322,7 @@ namespace Netch.Forms
|
||||
control.Checked = value;
|
||||
_saveActions.Add(control, c => save.Invoke(((CheckBox) c).Checked));
|
||||
}
|
||||
|
||||
private void BindRadioBox(RadioButton control, Action<bool> save, bool value)
|
||||
{
|
||||
control.Checked = value;
|
||||
@@ -385,12 +331,14 @@ namespace Netch.Forms
|
||||
|
||||
private void NoProxyForUdpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (NoProxyForUdpCheckBox.Checked) NoProxyForTcpCheckBox.Checked = false;
|
||||
if (NoProxyForUdpCheckBox.Checked)
|
||||
NoProxyForTcpCheckBox.Checked = false;
|
||||
}
|
||||
|
||||
private void NoProxyForTcpCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (NoProxyForTcpCheckBox.Checked) NoProxyForUdpCheckBox.Checked = false;
|
||||
if (NoProxyForTcpCheckBox.Checked)
|
||||
NoProxyForUdpCheckBox.Checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,8 @@ namespace Netch.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LinkTextBox.Text.StartsWith("HTTP://", StringComparison.OrdinalIgnoreCase) && !LinkTextBox.Text.StartsWith("HTTPS://", StringComparison.OrdinalIgnoreCase))
|
||||
if (!LinkTextBox.Text.StartsWith("HTTP://", StringComparison.OrdinalIgnoreCase) &&
|
||||
!LinkTextBox.Text.StartsWith("HTTPS://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MessageBoxX.Show(i18N.Translate("Link must start with http:// or https://"));
|
||||
return;
|
||||
@@ -124,7 +125,8 @@ namespace Netch.Forms
|
||||
|
||||
private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MessageBoxX.Show(i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), confirm: true) != DialogResult.OK)
|
||||
if (MessageBoxX.Show(i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"),
|
||||
confirm: true) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var subscribeLink = Global.Settings.SubscribeLink[SelectedIndex];
|
||||
@@ -188,6 +190,7 @@ namespace Netch.Forms
|
||||
LinkTextBox.Text = string.Empty;
|
||||
UserAgentTextBox.Text = WebUtil.DefaultUserAgent;
|
||||
}
|
||||
|
||||
private void SetEditingGroup(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
|
||||
121
Netch/Global.cs
121
Netch/Global.cs
@@ -20,6 +20,9 @@ namespace Netch
|
||||
/// </summary>
|
||||
public const string EOF = "\r\n";
|
||||
|
||||
public const string UserACL = "data\\user.acl";
|
||||
public const string BuiltinACL = "bin\\default.acl";
|
||||
|
||||
public static readonly string NetchDir = Application.StartupPath;
|
||||
|
||||
public static readonly string NetchExecutable = Application.ExecutablePath;
|
||||
@@ -31,74 +34,74 @@ namespace Netch
|
||||
|
||||
public static readonly Mutex Mutex = new(false, "Global\\Netch");
|
||||
|
||||
public static class Flags
|
||||
{
|
||||
public static bool SupportFakeDns => _supportFakeDns ??= new TUNTAPController().TestFakeDNS();
|
||||
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
private static bool? _supportFakeDns;
|
||||
}
|
||||
|
||||
public const string UserACL = "data\\user.acl";
|
||||
public const string BuiltinACL = "bin\\default.acl";
|
||||
|
||||
/// <summary>
|
||||
/// 出口适配器
|
||||
/// </summary>
|
||||
public static class Outbound
|
||||
{
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public static int Index = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public static IPAddress Address => Adapter.GetIPProperties().UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork).Address;
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public static IPAddress Gateway;
|
||||
|
||||
public static NetworkInterface Adapter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP 适配器
|
||||
/// </summary>
|
||||
public static class TUNTAP
|
||||
{
|
||||
/// <summary>
|
||||
/// 适配器
|
||||
/// </summary>
|
||||
public static NetworkInterface Adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public static int Index = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 组件 ID
|
||||
/// </summary>
|
||||
public static string ComponentID = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于读取和写入的配置
|
||||
/// </summary>
|
||||
public static Setting Settings = new Setting();
|
||||
public static Setting Settings = new();
|
||||
|
||||
/// <summary>
|
||||
/// 用于存储模式
|
||||
/// </summary>
|
||||
public static readonly List<Mode> Modes = new List<Mode>();
|
||||
public static readonly List<Mode> Modes = new();
|
||||
|
||||
/// <summary>
|
||||
/// Windows Job API
|
||||
/// Windows Job API
|
||||
/// </summary>
|
||||
public static readonly JobObject Job = new JobObject();
|
||||
public static readonly JobObject Job = new();
|
||||
|
||||
public static class Flags
|
||||
{
|
||||
public static readonly bool IsWindows10Upper = Environment.OSVersion.Version.Major >= 10;
|
||||
|
||||
private static bool? _supportFakeDns;
|
||||
|
||||
public static bool SupportFakeDns => _supportFakeDns ??= new TUNTAPController().TestFakeDNS();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出口适配器
|
||||
/// </summary>
|
||||
public static class Outbound
|
||||
{
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public static int Index = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 网关
|
||||
/// </summary>
|
||||
public static IPAddress Gateway;
|
||||
|
||||
public static NetworkInterface Adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public static IPAddress Address => Adapter.GetIPProperties()
|
||||
.UnicastAddresses.First(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
.Address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TUN/TAP 适配器
|
||||
/// </summary>
|
||||
public static class TUNTAP
|
||||
{
|
||||
/// <summary>
|
||||
/// 适配器
|
||||
/// </summary>
|
||||
public static NetworkInterface Adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
public static int Index = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 组件 ID
|
||||
/// </summary>
|
||||
public static string ComponentID = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,29 @@ namespace Netch.Models.GitHubRelease
|
||||
public class Asset
|
||||
{
|
||||
public string url { get; set; }
|
||||
|
||||
public int id { get; set; }
|
||||
|
||||
public string node_id { get; set; }
|
||||
|
||||
public string name { get; set; }
|
||||
|
||||
public object label { get; set; }
|
||||
|
||||
public GitHubUser uploader { get; set; }
|
||||
|
||||
public string content_type { get; set; }
|
||||
|
||||
public string state { get; set; }
|
||||
|
||||
public int size { get; set; }
|
||||
|
||||
public int download_count { get; set; }
|
||||
|
||||
public DateTime created_at { get; set; }
|
||||
|
||||
public DateTime updated_at { get; set; }
|
||||
|
||||
public string browser_download_url { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,12 @@
|
||||
private readonly string _owner;
|
||||
private readonly string _repo;
|
||||
|
||||
public string AllReleaseUrl => $@"https://api.github.com/repos/{_owner}/{_repo}/releases";
|
||||
|
||||
public GitHubRelease(string owner, string repo)
|
||||
{
|
||||
_owner = owner;
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
public string AllReleaseUrl => $@"https://api.github.com/repos/{_owner}/{_repo}/releases";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,39 @@
|
||||
public class GitHubUser
|
||||
{
|
||||
public string login { get; set; }
|
||||
|
||||
public int id { get; set; }
|
||||
|
||||
public string node_id { get; set; }
|
||||
|
||||
public string avatar_url { get; set; }
|
||||
|
||||
public string gravatar_id { get; set; }
|
||||
|
||||
public string url { get; set; }
|
||||
|
||||
public string html_url { get; set; }
|
||||
|
||||
public string followers_url { get; set; }
|
||||
|
||||
public string following_url { get; set; }
|
||||
|
||||
public string gists_url { get; set; }
|
||||
|
||||
public string starred_url { get; set; }
|
||||
|
||||
public string subscriptions_url { get; set; }
|
||||
|
||||
public string organizations_url { get; set; }
|
||||
|
||||
public string repos_url { get; set; }
|
||||
|
||||
public string events_url { get; set; }
|
||||
|
||||
public string received_events_url { get; set; }
|
||||
|
||||
public string type { get; set; }
|
||||
|
||||
public bool site_admin { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,22 +5,39 @@ namespace Netch.Models.GitHubRelease
|
||||
public class Release
|
||||
{
|
||||
public string url { get; set; }
|
||||
|
||||
public string assets_url { get; set; }
|
||||
|
||||
public string upload_url { get; set; }
|
||||
|
||||
public string html_url { get; set; }
|
||||
|
||||
public int id { get; set; }
|
||||
|
||||
public string node_id { get; set; }
|
||||
|
||||
public string tag_name { get; set; }
|
||||
|
||||
public string target_commitish { get; set; }
|
||||
|
||||
public string name { get; set; }
|
||||
|
||||
public bool draft { get; set; }
|
||||
|
||||
public GitHubUser author { get; set; }
|
||||
|
||||
public bool prerelease { get; set; }
|
||||
|
||||
public DateTime created_at { get; set; }
|
||||
|
||||
public DateTime published_at { get; set; }
|
||||
|
||||
public Asset[] assets { get; set; }
|
||||
|
||||
public string tarball_url { get; set; }
|
||||
|
||||
public string zipball_url { get; set; }
|
||||
|
||||
public string body { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@ namespace Netch.Models.GitHubRelease
|
||||
public struct SuffixVersion : ICloneable, IComparable, IComparable<SuffixVersion>, IEquatable<SuffixVersion>
|
||||
{
|
||||
public int Major { get; }
|
||||
|
||||
public int Minor { get; }
|
||||
|
||||
public int Patch { get; }
|
||||
|
||||
public string PreRelease { get; }
|
||||
|
||||
public int Build { get; }
|
||||
|
||||
public SuffixVersion(int major, int minor, int patch, string preRelease, int build)
|
||||
@@ -39,16 +43,10 @@ namespace Netch.Models.GitHubRelease
|
||||
|
||||
if (splitStr.Length > 1)
|
||||
foreach (var c in splitStr[1])
|
||||
{
|
||||
if (int.TryParse(c.ToString(), out var n))
|
||||
{
|
||||
build = build * 10 + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
preRelease.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return new SuffixVersion(dotNetVersion, preRelease.ToString(), build);
|
||||
}
|
||||
@@ -67,41 +65,49 @@ namespace Netch.Models.GitHubRelease
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public object Clone() => new SuffixVersion(Major, Major, Patch, PreRelease, Build);
|
||||
public object Clone()
|
||||
{
|
||||
return new SuffixVersion(Major, Major, Patch, PreRelease, Build);
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is SuffixVersion version)
|
||||
return CompareTo(version);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <returns>
|
||||
/// greater than 0 newer
|
||||
/// greater than 0 newer
|
||||
/// </returns>
|
||||
public int CompareTo(SuffixVersion other)
|
||||
{
|
||||
var majorComparison = Major.CompareTo(other.Major);
|
||||
if (majorComparison != 0)
|
||||
return majorComparison;
|
||||
|
||||
var minorComparison = Minor.CompareTo(other.Minor);
|
||||
if (minorComparison != 0)
|
||||
return minorComparison;
|
||||
|
||||
var patchComparison = Patch.CompareTo(other.Patch);
|
||||
if (patchComparison != 0)
|
||||
return patchComparison;
|
||||
|
||||
if (PreRelease == string.Empty)
|
||||
return other.PreRelease == string.Empty ? 0 : 1;
|
||||
|
||||
if (other.PreRelease == string.Empty)
|
||||
return -1;
|
||||
|
||||
var suffixComparison = string.Compare(PreRelease, other.PreRelease, StringComparison.Ordinal);
|
||||
if (suffixComparison != 0)
|
||||
return suffixComparison;
|
||||
|
||||
return Build.CompareTo(other.Build);
|
||||
}
|
||||
|
||||
@@ -115,7 +121,6 @@ namespace Netch.Models.GitHubRelease
|
||||
return obj is SuffixVersion other && Equals(other);
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
|
||||
@@ -9,4 +9,4 @@ namespace Netch.Models.GitHubRelease
|
||||
return VersionUtil.CompareVersion(x?.ToString(), y?.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,7 @@ namespace Netch.Models.GitHubRelease
|
||||
public static Release GetLatestRelease(IEnumerable<Release> releases, bool isPreRelease)
|
||||
{
|
||||
if (!isPreRelease)
|
||||
{
|
||||
releases = releases.Where(release => !release.prerelease);
|
||||
}
|
||||
|
||||
releases = releases.Where(release => IsVersionString(release.tag_name));
|
||||
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionComparer());
|
||||
|
||||
@@ -41,10 +41,12 @@ namespace Netch.Models
|
||||
/// <para />
|
||||
/// </summary>
|
||||
public int Type = 0;
|
||||
|
||||
public Mode(string fullName)
|
||||
{
|
||||
FullName = fullName;
|
||||
}
|
||||
|
||||
public Mode()
|
||||
{
|
||||
}
|
||||
@@ -63,6 +65,7 @@ namespace Netch.Models
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(s))
|
||||
continue;
|
||||
|
||||
if (s.StartsWith("//"))
|
||||
continue;
|
||||
|
||||
@@ -136,6 +139,7 @@ namespace Netch.Models
|
||||
return $"# {Remark}, {Type}, {(BypassChina ? 1 : 0)}{Global.EOF}{string.Join(Global.EOF, Rule)}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ModeExtension
|
||||
{
|
||||
/// 是否会转发 UDP
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
{
|
||||
public class Profile
|
||||
{
|
||||
public string ServerRemark;
|
||||
public int Index;
|
||||
public string ModeRemark;
|
||||
public string ProfileName;
|
||||
public int Index;
|
||||
public string ServerRemark;
|
||||
|
||||
public Profile(Server server, Mode mode, string name,int index)
|
||||
public Profile(Server server, Mode mode, string name, int index)
|
||||
{
|
||||
ServerRemark = server.Remark;
|
||||
ModeRemark = mode.Remark;
|
||||
@@ -16,12 +16,10 @@
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a dummy one.
|
||||
/// Return a dummy one.
|
||||
/// </summary>
|
||||
public Profile()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,9 @@ namespace Netch.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
return Global.Settings.ServerTCPing ? await Utils.Utils.TCPingAsync(destination, Port) : Utils.Utils.ICMPing(destination, Port);
|
||||
return Global.Settings.ServerTCPing
|
||||
? await Utils.Utils.TCPingAsync(destination, Port)
|
||||
: Utils.Utils.ICMPing(destination, Port);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
/// </summary>
|
||||
Stopped,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 退出中
|
||||
/// </summary>
|
||||
@@ -43,6 +42,7 @@
|
||||
{
|
||||
if (state == State.Waiting)
|
||||
return "Waiting for command";
|
||||
|
||||
return state.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
/// </summary>
|
||||
public bool Enable = true;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark;
|
||||
|
||||
/// <summary>
|
||||
/// 链接
|
||||
/// </summary>
|
||||
public string Link;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark;
|
||||
|
||||
/// <summary>
|
||||
/// User Agent
|
||||
/// </summary>
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Netch
|
||||
public static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建路由规则
|
||||
/// 创建路由规则
|
||||
/// </summary>
|
||||
/// <param name="address">目标地址</param>
|
||||
/// <param name="cidr">CIDR</param>
|
||||
@@ -17,7 +17,7 @@ namespace Netch
|
||||
public static extern bool CreateRoute(string address, int cidr, string gateway, int index, int metric = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 删除路由规则
|
||||
/// 删除路由规则
|
||||
/// </summary>
|
||||
/// <param name="address">目标地址</param>
|
||||
/// <param name="cidr">掩码地址</param>
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace Netch
|
||||
|
||||
// 设置当前目录
|
||||
Directory.SetCurrentDirectory(Global.NetchDir);
|
||||
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ";" + Path.Combine(Global.NetchDir, "bin"), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable("PATH",
|
||||
Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) + ";" + Path.Combine(Global.NetchDir, "bin"),
|
||||
EnvironmentVariableTarget.Process);
|
||||
|
||||
Updater.Updater.CleanOld();
|
||||
|
||||
|
||||
@@ -4,28 +4,16 @@ namespace Netch.Servers.Shadowsocks.Form
|
||||
{
|
||||
public class ShadowsocksForm : ServerForm
|
||||
{
|
||||
protected override string TypeName { get; } = "Shadowsocks";
|
||||
|
||||
public ShadowsocksForm(Shadowsocks server = default)
|
||||
{
|
||||
server ??= new Shadowsocks();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password",
|
||||
s => true,
|
||||
s => server.Password = s,
|
||||
server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method",
|
||||
SSGlobal.EncryptMethods,
|
||||
s => server.EncryptMethod = s,
|
||||
server.EncryptMethod);
|
||||
CreateTextBox("Plugin", "Plugin",
|
||||
s => true,
|
||||
s => server.Plugin = s,
|
||||
server.Plugin);
|
||||
CreateTextBox("PluginsOption", "Plugin Options",
|
||||
s => true,
|
||||
s => server.PluginOption = s,
|
||||
server.PluginOption);
|
||||
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", SSGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
CreateTextBox("Plugin", "Plugin", s => true, s => server.Plugin = s, server.Plugin);
|
||||
CreateTextBox("PluginsOption", "Plugin Options", s => true, s => server.PluginOption = s, server.PluginOption);
|
||||
}
|
||||
|
||||
protected override string TypeName { get; } = "Shadowsocks";
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,6 @@ namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
/// </summary>
|
||||
public string airport;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public ushort port;
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
@@ -34,6 +29,11 @@ namespace Netch.Servers.Shadowsocks.Models.SSD
|
||||
/// </summary>
|
||||
public string plugin_options;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public ushort port;
|
||||
|
||||
/// <summary>
|
||||
/// 服务器数组
|
||||
/// </summary>
|
||||
|
||||
@@ -2,16 +2,6 @@
|
||||
{
|
||||
public class SSDServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器地址
|
||||
/// </summary>
|
||||
public string server;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public ushort port;
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
@@ -32,9 +22,18 @@
|
||||
/// </summary>
|
||||
public string plugin_options;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public ushort port;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string remarks;
|
||||
/// <summary>
|
||||
/// 服务器地址
|
||||
/// </summary>
|
||||
public string server;
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,17 @@ namespace Netch.Servers.Shadowsocks.Models
|
||||
public class ShadowsocksConfig
|
||||
{
|
||||
public string server { get; set; }
|
||||
|
||||
public ushort server_port { get; set; }
|
||||
|
||||
public string password { get; set; }
|
||||
|
||||
public string method { get; set; }
|
||||
|
||||
public string remarks { get; set; }
|
||||
|
||||
public string plugin { get; set; }
|
||||
|
||||
public string plugin_opts { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,14 +11,17 @@ namespace Netch.Servers.Shadowsocks
|
||||
public class SSController : Guard, IServerController
|
||||
{
|
||||
public bool DllFlag;
|
||||
|
||||
public override string MainFile { get; protected set; } = "Shadowsocks.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; } = new[] {"listening at"};
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; } = new[] {"Invalid config path", "usage", "plugin service exit unexpectedly"};
|
||||
|
||||
public override string Name { get; } = "Shadowsocks";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
@@ -57,17 +60,12 @@ namespace Netch.Servers.Shadowsocks
|
||||
#region Argument
|
||||
|
||||
var argument = new StringBuilder();
|
||||
argument.Append(
|
||||
$"-s {server.AutoResolveHostname()} " +
|
||||
$"-p {server.Port} " +
|
||||
$"-b {this.LocalAddress()} " +
|
||||
$"-l {this.Socks5LocalPort()} " +
|
||||
$"-m {server.EncryptMethod} " +
|
||||
$"-k \"{server.Password}\" " +
|
||||
"-u");
|
||||
argument.Append($"-s {server.AutoResolveHostname()} " + $"-p {server.Port} " + $"-b {this.LocalAddress()} " +
|
||||
$"-l {this.Socks5LocalPort()} " + $"-m {server.EncryptMethod} " + $"-k \"{server.Password}\" " + "-u");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(server.Plugin) && !string.IsNullOrWhiteSpace(server.PluginOption))
|
||||
argument.Append($" --plugin {server.Plugin}" +
|
||||
$" --plugin-opts \"{server.PluginOption}\"");
|
||||
argument.Append($" --plugin {server.Plugin}" + $" --plugin-opts \"{server.PluginOption}\"");
|
||||
|
||||
if (mode.BypassChina)
|
||||
argument.Append($" --acl {Path.GetFullPath(File.Exists(Global.UserACL) ? Global.UserACL : Global.BuiltinACL)}");
|
||||
|
||||
|
||||
@@ -16,9 +16,13 @@ namespace Netch.Servers.Shadowsocks
|
||||
public class SSUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 1;
|
||||
|
||||
public string TypeName { get; } = "SS";
|
||||
|
||||
public string FullName { get; } = "Shadowsocks";
|
||||
|
||||
public string ShortName { get; } = "SS";
|
||||
|
||||
public string[] UriScheme { get; } = {"ss", "ssd"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
@@ -40,7 +44,8 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
// ss://method:password@server:port#Remark
|
||||
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" + HttpUtility.UrlEncode(server.Remark);
|
||||
return "ss://" + ShareLink.URLSafeBase64Encode($"{server.EncryptMethod}:{server.Password}@{server.Hostname}:{server.Port}") + "#" +
|
||||
HttpUtility.UrlEncode(server.Remark);
|
||||
}
|
||||
|
||||
public IServerController GetController()
|
||||
@@ -51,18 +56,28 @@ namespace Netch.Servers.Shadowsocks
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
if (text.StartsWith("ss://"))
|
||||
{
|
||||
return new[] {ParseSsUri(text)};
|
||||
}
|
||||
|
||||
if (text.StartsWith("ssd://"))
|
||||
{
|
||||
return ParseSsdUri(text);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<Server> ParseSsdUri(string s)
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)));
|
||||
@@ -75,7 +90,9 @@ namespace Netch.Servers.Shadowsocks
|
||||
Password = server.password ?? json.password,
|
||||
EncryptMethod = server.encryption ?? json.encryption,
|
||||
Plugin = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin,
|
||||
PluginOption = string.IsNullOrEmpty(json.plugin_options) ? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options : json.plugin_options
|
||||
PluginOption = string.IsNullOrEmpty(json.plugin_options)
|
||||
? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options
|
||||
: json.plugin_options
|
||||
})
|
||||
.Where(CheckServer);
|
||||
}
|
||||
@@ -112,11 +129,13 @@ namespace Netch.Servers.Shadowsocks
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=http;obfs-host=" + pluginopts;
|
||||
|
||||
break;
|
||||
case "simple-obfs-tls":
|
||||
plugin = "simple-obfs";
|
||||
if (!pluginopts.Contains("obfs="))
|
||||
pluginopts = "obfs=tls;obfs-host=" + pluginopts;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -137,14 +156,16 @@ namespace Netch.Servers.Shadowsocks
|
||||
var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success) throw new FormatException();
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
|
||||
var base64 = ShareLink.URLSafeBase64Decode(match.Groups["base64"].Value);
|
||||
match = parser.Match(base64);
|
||||
if (!match.Success) throw new FormatException();
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.EncryptMethod = match.Groups["method"].Value;
|
||||
data.Password = match.Groups["password"].Value;
|
||||
@@ -153,7 +174,8 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
var parser = new Regex(@"^((?<method>.+?):(?<password>.+)@(?<server>.+):(?<port>\d+))");
|
||||
var match = parser.Match(ShareLink.URLSafeBase64Decode(text.Replace("ss://", "")));
|
||||
if (!match.Success) throw new FormatException();
|
||||
if (!match.Success)
|
||||
throw new FormatException();
|
||||
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
data.Port = ushort.Parse(match.Groups["port"].Value);
|
||||
@@ -168,19 +190,5 @@ namespace Netch.Servers.Shadowsocks
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckServer(Server s)
|
||||
{
|
||||
var server = (Shadowsocks) s;
|
||||
if (!SSGlobal.EncryptMethods.Contains(server.EncryptMethod))
|
||||
{
|
||||
Logging.Error($"不支持的 SS 加密方式:{server.EncryptMethod}");
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,11 @@ namespace Netch.Servers.Shadowsocks
|
||||
{
|
||||
public class Shadowsocks : Server
|
||||
{
|
||||
public Shadowsocks()
|
||||
{
|
||||
Type = "SS";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
@@ -25,12 +30,10 @@ namespace Netch.Servers.Shadowsocks
|
||||
/// </summary>
|
||||
public string PluginOption { get; set; }
|
||||
|
||||
public Shadowsocks()
|
||||
public bool HasPlugin()
|
||||
{
|
||||
Type = "SS";
|
||||
return !string.IsNullOrWhiteSpace(Plugin) && !string.IsNullOrWhiteSpace(PluginOption);
|
||||
}
|
||||
|
||||
public bool HasPlugin() => !string.IsNullOrWhiteSpace(Plugin) && !string.IsNullOrWhiteSpace(PluginOption);
|
||||
}
|
||||
|
||||
public static class SSGlobal
|
||||
@@ -38,7 +41,7 @@ namespace Netch.Servers.Shadowsocks
|
||||
/// <summary>
|
||||
/// SS 加密列表
|
||||
/// </summary>
|
||||
public static readonly List<string> EncryptMethods = new List<string>
|
||||
public static readonly List<string> EncryptMethods = new()
|
||||
{
|
||||
"rc4-md5",
|
||||
"aes-128-gcm",
|
||||
|
||||
@@ -4,36 +4,18 @@ namespace Netch.Servers.ShadowsocksR.Form
|
||||
{
|
||||
public class ShadowsocksRForm : ServerForm
|
||||
{
|
||||
protected override string TypeName { get; } = "ShadowsocksR";
|
||||
|
||||
public ShadowsocksRForm(ShadowsocksR server = default)
|
||||
{
|
||||
server ??= new ShadowsocksR();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password",
|
||||
s => true,
|
||||
s => server.Password = s,
|
||||
server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method",
|
||||
SSRGlobal.EncryptMethods,
|
||||
s => server.EncryptMethod = s,
|
||||
server.EncryptMethod);
|
||||
CreateComboBox("Protocol", "Protocol",
|
||||
SSRGlobal.Protocols,
|
||||
s => server.Protocol = s,
|
||||
server.Protocol);
|
||||
CreateTextBox("ProtocolParam", "Protocol Param",
|
||||
s => true,
|
||||
s => server.ProtocolParam = s,
|
||||
server.ProtocolParam);
|
||||
CreateComboBox("OBFS", "OBFS",
|
||||
SSRGlobal.OBFSs,
|
||||
s => server.OBFS = s,
|
||||
server.OBFS);
|
||||
CreateTextBox("OBFSParam", "OBFS Param",
|
||||
s => true,
|
||||
s => server.OBFSParam = s,
|
||||
server.OBFSParam);
|
||||
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", SSRGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
CreateComboBox("Protocol", "Protocol", SSRGlobal.Protocols, s => server.Protocol = s, server.Protocol);
|
||||
CreateTextBox("ProtocolParam", "Protocol Param", s => true, s => server.ProtocolParam = s, server.ProtocolParam);
|
||||
CreateComboBox("OBFS", "OBFS", SSRGlobal.OBFSs, s => server.OBFS = s, server.OBFS);
|
||||
CreateTextBox("OBFSParam", "OBFS Param", s => true, s => server.OBFSParam = s, server.OBFSParam);
|
||||
}
|
||||
|
||||
protected override string TypeName { get; } = "ShadowsocksR";
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
public override string Name { get; } = "ShadowsocksR";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
@@ -30,13 +31,15 @@ namespace Netch.Servers.ShadowsocksR
|
||||
if (!string.IsNullOrEmpty(server.Protocol))
|
||||
{
|
||||
argument.Append($" -O {server.Protocol}");
|
||||
if (!string.IsNullOrEmpty(server.ProtocolParam)) argument.Append($" -G \"{server.ProtocolParam}\"");
|
||||
if (!string.IsNullOrEmpty(server.ProtocolParam))
|
||||
argument.Append($" -G \"{server.ProtocolParam}\"");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(server.OBFS))
|
||||
{
|
||||
argument.Append($" -o {server.OBFS}");
|
||||
if (!string.IsNullOrEmpty(server.OBFSParam)) argument.Append($" -g \"{server.OBFSParam}\"");
|
||||
if (!string.IsNullOrEmpty(server.OBFSParam))
|
||||
argument.Append($" -g \"{server.OBFSParam}\"");
|
||||
}
|
||||
|
||||
argument.Append($" -b {this.LocalAddress()} -l {this.Socks5LocalPort()} -u");
|
||||
|
||||
@@ -13,9 +13,13 @@ namespace Netch.Servers.ShadowsocksR
|
||||
public class SSRUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 1;
|
||||
|
||||
public string TypeName { get; } = "SSR";
|
||||
|
||||
public string FullName { get; } = "ShadowsocksR";
|
||||
|
||||
public string ShortName { get; } = "SR";
|
||||
|
||||
public string[] UriScheme { get; } = {"ssr"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
@@ -23,7 +27,6 @@ namespace Netch.Servers.ShadowsocksR
|
||||
return j.ToObject<ShadowsocksR>();
|
||||
}
|
||||
|
||||
|
||||
public void Edit(Server s)
|
||||
{
|
||||
new ShadowsocksRForm((ShadowsocksR) s).ShowDialog();
|
||||
@@ -40,8 +43,12 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
// https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
|
||||
// ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
||||
var paraStr = $"/?obfsparam={ShareLink.URLSafeBase64Encode(server.OBFSParam)}&protoparam={ShareLink.URLSafeBase64Encode(server.ProtocolParam)}&remarks={ShareLink.URLSafeBase64Encode(server.Remark)}";
|
||||
return "ssr://" + ShareLink.URLSafeBase64Encode($"{server.Hostname}:{server.Port}:{server.Protocol}:{server.EncryptMethod}:{server.OBFS}:{ShareLink.URLSafeBase64Encode(server.Password)}{paraStr}");
|
||||
var paraStr =
|
||||
$"/?obfsparam={ShareLink.URLSafeBase64Encode(server.OBFSParam)}&protoparam={ShareLink.URLSafeBase64Encode(server.ProtocolParam)}&remarks={ShareLink.URLSafeBase64Encode(server.Remark)}";
|
||||
|
||||
return "ssr://" +
|
||||
ShareLink.URLSafeBase64Encode(
|
||||
$"{server.Hostname}:{server.Port}:{server.Protocol}:{server.EncryptMethod}:{server.OBFS}:{ShareLink.URLSafeBase64Encode(server.Password)}{paraStr}");
|
||||
}
|
||||
|
||||
public IServerController GetController()
|
||||
@@ -51,7 +58,8 @@ namespace Netch.Servers.ShadowsocksR
|
||||
|
||||
/// <summary>
|
||||
/// SSR链接解析器
|
||||
/// Copy From https://github.com/HMBSbige/ShadowsocksR-Windows/blob/d9dc8d032a6e04c14b9dc6c8f673c9cc5aa9f607/shadowsocks-csharp/Model/Server.cs#L428
|
||||
/// Copy From
|
||||
/// https://github.com/HMBSbige/ShadowsocksR-Windows/blob/d9dc8d032a6e04c14b9dc6c8f673c9cc5aa9f607/shadowsocks-csharp/Model/Server.cs#L428
|
||||
/// Thx :D
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
@@ -73,7 +81,8 @@ namespace Netch.Servers.ShadowsocksR
|
||||
data = data.Substring(0, paramStartPos);
|
||||
}
|
||||
|
||||
if (data.IndexOf("/", StringComparison.Ordinal) >= 0) data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal));
|
||||
if (data.IndexOf("/", StringComparison.Ordinal) >= 0)
|
||||
data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal));
|
||||
|
||||
var urlFinder = new Regex("^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)");
|
||||
var match = urlFinder.Match(data);
|
||||
@@ -93,16 +102,18 @@ namespace Netch.Servers.ShadowsocksR
|
||||
var obfsParam = "";
|
||||
var remarks = "";
|
||||
|
||||
if (paramsDict.ContainsKey("protoparam")) protocolParam = ShareLink.URLSafeBase64Decode(paramsDict["protoparam"]);
|
||||
if (paramsDict.ContainsKey("protoparam"))
|
||||
protocolParam = ShareLink.URLSafeBase64Decode(paramsDict["protoparam"]);
|
||||
|
||||
if (paramsDict.ContainsKey("obfsparam")) obfsParam = ShareLink.URLSafeBase64Decode(paramsDict["obfsparam"]);
|
||||
if (paramsDict.ContainsKey("obfsparam"))
|
||||
obfsParam = ShareLink.URLSafeBase64Decode(paramsDict["obfsparam"]);
|
||||
|
||||
if (paramsDict.ContainsKey("remarks")) remarks = ShareLink.URLSafeBase64Decode(paramsDict["remarks"]);
|
||||
if (paramsDict.ContainsKey("remarks"))
|
||||
remarks = ShareLink.URLSafeBase64Decode(paramsDict["remarks"]);
|
||||
|
||||
var group = paramsDict.ContainsKey("group") ? ShareLink.URLSafeBase64Decode(paramsDict["group"]) : string.Empty;
|
||||
|
||||
if (SSGlobal.EncryptMethods.Contains(method) && protocol == "origin" && obfs == "plain")
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new Shadowsocks.Shadowsocks
|
||||
@@ -115,7 +126,6 @@ namespace Netch.Servers.ShadowsocksR
|
||||
Group = group
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new[]
|
||||
{
|
||||
|
||||
@@ -5,6 +5,11 @@ namespace Netch.Servers.ShadowsocksR
|
||||
{
|
||||
public class ShadowsocksR : Server
|
||||
{
|
||||
public ShadowsocksR()
|
||||
{
|
||||
Type = "SSR";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密方式
|
||||
/// </summary>
|
||||
@@ -34,11 +39,6 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// 协议参数
|
||||
/// </summary>
|
||||
public string ProtocolParam { get; set; }
|
||||
|
||||
public ShadowsocksR()
|
||||
{
|
||||
Type = "SSR";
|
||||
}
|
||||
}
|
||||
|
||||
public class SSRGlobal
|
||||
@@ -46,7 +46,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// <summary>
|
||||
/// SSR 协议列表
|
||||
/// </summary>
|
||||
public static readonly List<string> Protocols = new List<string>
|
||||
public static readonly List<string> Protocols = new()
|
||||
{
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
@@ -59,7 +59,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// <summary>
|
||||
/// SSR 混淆列表
|
||||
/// </summary>
|
||||
public static readonly List<string> OBFSs = new List<string>
|
||||
public static readonly List<string> OBFSs = new()
|
||||
{
|
||||
"plain",
|
||||
"http_simple",
|
||||
@@ -70,7 +70,7 @@ namespace Netch.Servers.ShadowsocksR
|
||||
/// <summary>
|
||||
/// SS/SSR 加密方式
|
||||
/// </summary>
|
||||
public static readonly List<string> EncryptMethods = new List<string>
|
||||
public static readonly List<string> EncryptMethods = new()
|
||||
{
|
||||
"none",
|
||||
"table",
|
||||
|
||||
@@ -4,20 +4,14 @@ namespace Netch.Servers.Socks5.Form
|
||||
{
|
||||
public class Socks5Form : ServerForm
|
||||
{
|
||||
protected override string TypeName { get; } = "Socks5";
|
||||
|
||||
public Socks5Form(Socks5 server = default)
|
||||
{
|
||||
server ??= new Socks5();
|
||||
Server = server;
|
||||
CreateTextBox("Username", "Username",
|
||||
s => true,
|
||||
s => server.Username = s,
|
||||
server.Username);
|
||||
CreateTextBox("Password", "Password",
|
||||
s => true,
|
||||
s => server.Password = s,
|
||||
server.Password);
|
||||
CreateTextBox("Username", "Username", s => true, s => server.Username = s, server.Username);
|
||||
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
|
||||
}
|
||||
|
||||
protected override string TypeName { get; } = "Socks5";
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,13 @@ namespace Netch.Servers.Socks5
|
||||
public class S5Util : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 0;
|
||||
|
||||
public string TypeName { get; } = "Socks5";
|
||||
|
||||
public string FullName { get; } = "Socks5";
|
||||
|
||||
public string ShortName { get; } = "S5";
|
||||
|
||||
public string[] UriScheme { get; } = { };
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
@@ -46,17 +50,14 @@ namespace Netch.Servers.Socks5
|
||||
|
||||
public IEnumerable<Server> ParseUri(string text)
|
||||
{
|
||||
var dict = text
|
||||
.Replace("tg://socks?", "")
|
||||
var dict = text.Replace("tg://socks?", "")
|
||||
.Replace("https://t.me/socks?", "")
|
||||
.Split('&')
|
||||
.Select(str => str.Split('='))
|
||||
.ToDictionary(splited => splited[0], splited => splited[1]);
|
||||
|
||||
if (!dict.ContainsKey("server") || !dict.ContainsKey("port"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = new Socks5
|
||||
{
|
||||
@@ -65,14 +66,10 @@ namespace Netch.Servers.Socks5
|
||||
};
|
||||
|
||||
if (dict.ContainsKey("user") && !string.IsNullOrWhiteSpace(dict["user"]))
|
||||
{
|
||||
data.Username = dict["user"];
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("pass") && !string.IsNullOrWhiteSpace(dict["pass"]))
|
||||
{
|
||||
data.Password = dict["pass"];
|
||||
}
|
||||
|
||||
return new[] {data};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace Netch.Servers.Socks5
|
||||
Type = "Socks5";
|
||||
}
|
||||
|
||||
public bool Auth() => !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password);
|
||||
public bool Auth()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,14 @@ namespace Netch.Servers.Trojan.Form
|
||||
{
|
||||
public class TrojanForm : ServerForm
|
||||
{
|
||||
protected override string TypeName { get; } = "Trojan";
|
||||
|
||||
public TrojanForm(Trojan server = default)
|
||||
{
|
||||
server ??= new Trojan();
|
||||
Server = server;
|
||||
CreateTextBox("Password", "Password",
|
||||
s => true,
|
||||
s => server.Password = s,
|
||||
server.Password);
|
||||
CreateTextBox("Host", "Host",
|
||||
s => true,
|
||||
s => server.Host = s,
|
||||
server.Host);
|
||||
CreateTextBox("Password", "Password", s => true, s => server.Password = s, server.Password);
|
||||
CreateTextBox("Host", "Host", s => true, s => server.Host = s, server.Host);
|
||||
}
|
||||
|
||||
protected override string TypeName { get; } = "Trojan";
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,6 @@ namespace Netch.Servers.Trojan.Models
|
||||
{
|
||||
public class TrojanConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动类型
|
||||
/// </summary>
|
||||
public string run_type = "client";
|
||||
|
||||
/// <summary>
|
||||
/// 监听地址
|
||||
/// </summary>
|
||||
@@ -19,6 +14,16 @@ namespace Netch.Servers.Trojan.Models
|
||||
/// </summary>
|
||||
public int local_port = 2801;
|
||||
|
||||
/// <summary>
|
||||
/// 日志级别
|
||||
/// </summary>
|
||||
public int log_level = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public List<string> password;
|
||||
|
||||
/// <summary>
|
||||
/// 远端地址
|
||||
/// </summary>
|
||||
@@ -28,47 +33,41 @@ namespace Netch.Servers.Trojan.Models
|
||||
/// 远端端口
|
||||
/// </summary>
|
||||
public int remote_port;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// 启动类型
|
||||
/// </summary>
|
||||
public List<string> password;
|
||||
public string run_type = "client";
|
||||
|
||||
/// <summary>
|
||||
/// 日志级别
|
||||
/// </summary>
|
||||
public int log_level = 1;
|
||||
|
||||
public TrojanSSL ssl = new TrojanSSL();
|
||||
public TrojanTCP tcp = new TrojanTCP();
|
||||
public TrojanSSL ssl = new();
|
||||
public TrojanTCP tcp = new();
|
||||
}
|
||||
|
||||
public class TrojanSSL
|
||||
{
|
||||
public bool verify = false;
|
||||
public bool verify_hostname = false;
|
||||
public string cert;
|
||||
public string cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
|
||||
public string cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384";
|
||||
public string sni = string.Empty;
|
||||
|
||||
public List<string> alpn = new List<string>
|
||||
public List<string> alpn = new()
|
||||
{
|
||||
"h2",
|
||||
"http/1.1"
|
||||
};
|
||||
public string cert;
|
||||
public string cipher =
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
|
||||
public string cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384";
|
||||
public string curves = "";
|
||||
|
||||
public bool reuse_session = true;
|
||||
public bool session_ticket = true;
|
||||
public string curves = "";
|
||||
public string sni = string.Empty;
|
||||
public bool verify = false;
|
||||
public bool verify_hostname = false;
|
||||
}
|
||||
|
||||
public class TrojanTCP
|
||||
{
|
||||
public bool no_delay = false;
|
||||
public bool keep_alive = true;
|
||||
public bool reuse_port = false;
|
||||
public bool fast_open = true;
|
||||
public int fast_open_qlen = 20;
|
||||
public bool keep_alive = true;
|
||||
public bool no_delay = false;
|
||||
public bool reuse_port = false;
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,15 @@ namespace Netch.Servers.Trojan
|
||||
public class TrojanController : Guard, IServerController
|
||||
{
|
||||
public override string MainFile { get; protected set; } = "Trojan.exe";
|
||||
|
||||
protected override IEnumerable<string> StartedKeywords { get; } = new[] {"started"};
|
||||
|
||||
protected override IEnumerable<string> StoppedKeywords { get; } = new[] {"exiting"};
|
||||
|
||||
public override string Name { get; } = "Trojan";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
public void Start(in Server s, in Mode mode)
|
||||
@@ -35,10 +39,14 @@ namespace Netch.Servers.Trojan
|
||||
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
|
||||
}));
|
||||
File.WriteAllText("data\\last.json",
|
||||
JsonConvert.SerializeObject(trojanConfig,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}));
|
||||
|
||||
StartInstanceAuto("-c ..\\data\\last.json");
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,13 @@ namespace Netch.Servers.Trojan
|
||||
public class TrojanUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 3;
|
||||
|
||||
public string TypeName { get; } = "Trojan";
|
||||
|
||||
public string FullName { get; } = "Trojan";
|
||||
|
||||
public string ShortName { get; } = "TR";
|
||||
|
||||
public string[] UriScheme { get; } = {"trojan"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
@@ -79,9 +83,7 @@ namespace Netch.Servers.Trojan
|
||||
var finder = new Regex(@"^trojan://(?<psk>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
data.Password = match.Groups["psk"].Value;
|
||||
data.Hostname = match.Groups["server"].Value;
|
||||
|
||||
@@ -207,24 +207,22 @@ namespace Netch.Servers.V2ray.Models
|
||||
|
||||
public class TCPRequest
|
||||
{
|
||||
public string version = "1.1";
|
||||
public TCPRequestHeaders headers;
|
||||
|
||||
public string method = "GET";
|
||||
|
||||
public string path = "/";
|
||||
|
||||
public TCPRequestHeaders headers;
|
||||
public string version = "1.1";
|
||||
}
|
||||
|
||||
public class TCPRequestHeaders
|
||||
{
|
||||
public string Host;
|
||||
|
||||
//public string User_Agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36";
|
||||
|
||||
public string Accept_Encoding = "gzip, deflate";
|
||||
|
||||
public string Connection = "keep-alive";
|
||||
public string Host;
|
||||
|
||||
public string Pragma = "no-cache";
|
||||
}
|
||||
|
||||
@@ -5,59 +5,58 @@
|
||||
/// </summary>
|
||||
public class V2rayNSharing
|
||||
{
|
||||
/// <summary>
|
||||
/// 链接版本
|
||||
/// </summary>
|
||||
public string v = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string ps = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
public string add = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public string port = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID
|
||||
/// </summary>
|
||||
public string id = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 额外 ID
|
||||
/// </summary>
|
||||
public string aid = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议
|
||||
/// </summary>
|
||||
public string net = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public string type = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装域名(HTTP,WS)
|
||||
/// </summary>
|
||||
public string host = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 用户 ID
|
||||
/// </summary>
|
||||
public string id = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 传输协议
|
||||
/// </summary>
|
||||
public string net = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装路径
|
||||
/// </summary>
|
||||
public string path = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
public string port = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string ps = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用 TLS
|
||||
/// </summary>
|
||||
public string tls = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 伪装类型
|
||||
/// </summary>
|
||||
public string type = string.Empty;
|
||||
/// <summary>
|
||||
/// 链接版本
|
||||
/// </summary>
|
||||
public string v = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,9 @@ namespace Netch.Servers.V2ray.Utils
|
||||
|
||||
outbound(server, mode, ref v2rayConfig);
|
||||
|
||||
return JsonConvert.SerializeObject(v2rayConfig, Formatting.Indented, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
|
||||
return JsonConvert.SerializeObject(v2rayConfig,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -87,6 +89,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
directRuleObject.domain.Add("geosite:cn");
|
||||
else
|
||||
directRuleObject.ip.Add("geoip:cn");
|
||||
|
||||
break;
|
||||
default:
|
||||
directRuleObject.domain.Add("geosite:cn");
|
||||
@@ -115,6 +118,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
|
||||
if (CheckRuleItem(ref directRuleObject))
|
||||
v2rayConfig.routing.rules.Add(directRuleObject);
|
||||
|
||||
if (CheckRuleItem(ref blockRuleObject))
|
||||
v2rayConfig.routing.rules.Add(blockRuleObject);
|
||||
}
|
||||
@@ -175,6 +179,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
|
||||
outbound.settings.vnext = new List<VnextItem> {vnextItem};
|
||||
|
||||
var usersItem = new UsersItem
|
||||
@@ -184,6 +189,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
flow = string.Empty,
|
||||
encryption = vless.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
@@ -214,6 +220,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
address = server.AutoResolveHostname(),
|
||||
port = server.Port
|
||||
};
|
||||
|
||||
outbound.settings.vnext = new List<VnextItem> {vnextItem};
|
||||
|
||||
var usersItem = new UsersItem
|
||||
@@ -222,6 +229,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
alterId = vmess.AlterID,
|
||||
security = vmess.EncryptMethod
|
||||
};
|
||||
|
||||
vnextItem.users.Add(usersItem);
|
||||
|
||||
var streamSettings = outbound.streamSettings;
|
||||
@@ -302,9 +310,7 @@ namespace Netch.Servers.V2ray.Utils
|
||||
case "ws":
|
||||
var wsSettings = new WsSettings
|
||||
{
|
||||
headers = !string.IsNullOrWhiteSpace(server.Host)
|
||||
? new Headers {Host = server.Host}
|
||||
: null,
|
||||
headers = !string.IsNullOrWhiteSpace(server.Host) ? new Headers {Host = server.Host} : null,
|
||||
path = !string.IsNullOrWhiteSpace(server.Path) ? server.Path : null
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace Netch.Servers.V2ray
|
||||
public override string Name { get; } = "Xray";
|
||||
|
||||
public ushort? Socks5LocalPort { get; set; }
|
||||
|
||||
public string LocalAddress { get; set; }
|
||||
|
||||
public virtual void Start(in Server s, in Mode mode)
|
||||
{
|
||||
File.WriteAllText("data\\last.json", V2rayConfigUtils.GenerateClientConfig(s, mode));
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace Netch.Servers.V2ray
|
||||
server.FakeType = parameter.Get("headerType") ?? "none";
|
||||
break;
|
||||
}
|
||||
|
||||
server.TLSSecureType = parameter.Get("security") ?? "none";
|
||||
if (server.TLSSecureType != "none")
|
||||
{
|
||||
@@ -58,6 +59,7 @@ namespace Netch.Servers.V2ray
|
||||
((VLESS.VLESS) server).Flow = parameter.Get("flow") ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
var finder = new Regex(@$"^{scheme}://(?<guid>.+?)@(?<server>.+):(?<port>\d+)");
|
||||
var match = finder.Match(text.Split('?')[0]);
|
||||
if (!match.Success)
|
||||
@@ -78,6 +80,7 @@ namespace Netch.Servers.V2ray
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetVShareLink(Server s, string scheme = "vmess")
|
||||
{
|
||||
var server = (VMess.VMess) s;
|
||||
@@ -87,6 +90,7 @@ namespace Netch.Servers.V2ray
|
||||
if (server.EncryptMethod == "none")
|
||||
// VLESS outbounds[].settings.encryption,当前可选值只有 none
|
||||
parameter.Add("encryption", server.EncryptMethod);
|
||||
|
||||
// transport-specific fields
|
||||
switch (server.TransferProtocol)
|
||||
{
|
||||
@@ -95,18 +99,22 @@ namespace Netch.Servers.V2ray
|
||||
case "kcp":
|
||||
if (server.FakeType != "none")
|
||||
parameter.Add("headerType", server.FakeType);
|
||||
|
||||
if (!server.Path.IsNullOrWhiteSpace())
|
||||
parameter.Add("seed", Uri.EscapeDataString(server.Path));
|
||||
|
||||
break;
|
||||
case "ws":
|
||||
parameter.Add("path", Uri.EscapeDataString(server.Path.IsNullOrWhiteSpace() ? "/" : server.Path));
|
||||
if (!server.Host.IsNullOrWhiteSpace())
|
||||
parameter.Add("host", server.Host);
|
||||
|
||||
break;
|
||||
case "h2":
|
||||
parameter.Add("path", Uri.EscapeDataString(server.Path.IsNullOrWhiteSpace() ? "/" : server.Path));
|
||||
if (!server.Host.IsNullOrWhiteSpace())
|
||||
parameter.Add("host", Uri.EscapeDataString(server.Host));
|
||||
|
||||
break;
|
||||
case "quic":
|
||||
if (server.QUICSecure != "none")
|
||||
@@ -117,6 +125,7 @@ namespace Netch.Servers.V2ray
|
||||
|
||||
if (server.FakeType != "none")
|
||||
parameter.Add("headerType", server.FakeType);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -135,7 +144,8 @@ namespace Netch.Servers.V2ray
|
||||
}
|
||||
}
|
||||
|
||||
return $"{scheme}://{server.UserID}@{server.Hostname}:{server.Port}?{string.Join("&", parameter.Select(p => $"{p.Key}={p.Value}"))}{(server.Remark.IsNullOrWhiteSpace() ? "" : $"#{Uri.EscapeDataString(server.Remark)}")}";
|
||||
return
|
||||
$"{scheme}://{server.UserID}@{server.Hostname}:{server.Port}?{string.Join("&", parameter.Select(p => $"{p.Key}={p.Value}"))}{(server.Remark.IsNullOrWhiteSpace() ? "" : $"#{Uri.EscapeDataString(server.Remark)}")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,9 @@ namespace Netch.Servers.VLESS
|
||||
"tls",
|
||||
"xtls"
|
||||
};
|
||||
|
||||
public static List<string> FakeTypes => VMessGlobal.FakeTypes;
|
||||
|
||||
public static List<string> TransferProtocols => VMessGlobal.TransferProtocols;
|
||||
|
||||
public static List<string> QUIC => VMessGlobal.QUIC;
|
||||
|
||||
@@ -9,57 +9,34 @@ namespace Netch.Servers.VLESS.VLESSForm
|
||||
{
|
||||
server ??= new VLESS();
|
||||
Server = server;
|
||||
CreateTextBox("UUID", "UUID",
|
||||
s => true,
|
||||
s => server.UserID = s,
|
||||
server.UserID);
|
||||
CreateTextBox("EncryptMethod", "Encrypt Method",
|
||||
CreateTextBox("UUID", "UUID", s => true, s => server.UserID = s, server.UserID);
|
||||
CreateTextBox("EncryptMethod",
|
||||
"Encrypt Method",
|
||||
s => true,
|
||||
s => server.EncryptMethod = !string.IsNullOrWhiteSpace(s) ? s : "none",
|
||||
server.EncryptMethod);
|
||||
CreateTextBox("Flow", "Flow",
|
||||
s => true,
|
||||
s => server.Flow = s,
|
||||
server.Flow);
|
||||
CreateComboBox("TransferProtocol", "Transfer Protocol",
|
||||
|
||||
CreateTextBox("Flow", "Flow", s => true, s => server.Flow = s, server.Flow);
|
||||
CreateComboBox("TransferProtocol",
|
||||
"Transfer Protocol",
|
||||
VLESSGlobal.TransferProtocols,
|
||||
s => server.TransferProtocol = s,
|
||||
server.TransferProtocol);
|
||||
CreateComboBox("FakeType", "Fake Type",
|
||||
VLESSGlobal.FakeTypes,
|
||||
s => server.FakeType = s,
|
||||
server.FakeType);
|
||||
CreateTextBox("Host", "Host",
|
||||
s => true,
|
||||
s => server.Host = s,
|
||||
server.Host);
|
||||
CreateTextBox("Path", "Path",
|
||||
s => true,
|
||||
s => server.Path = s,
|
||||
server.Path);
|
||||
CreateComboBox("QUICSecurity", "QUIC Security",
|
||||
VLESSGlobal.QUIC,
|
||||
s => server.QUICSecure = s,
|
||||
server.QUICSecure);
|
||||
CreateTextBox("QUICSecret", "QUIC Secret",
|
||||
s => true,
|
||||
s => server.QUICSecret = s,
|
||||
server.QUICSecret);
|
||||
CreateComboBox("UseMux", "Use Mux",
|
||||
|
||||
CreateComboBox("FakeType", "Fake Type", VLESSGlobal.FakeTypes, s => server.FakeType = s, server.FakeType);
|
||||
CreateTextBox("Host", "Host", s => true, s => server.Host = s, server.Host);
|
||||
CreateTextBox("Path", "Path", s => true, s => server.Path = s, server.Path);
|
||||
CreateComboBox("QUICSecurity", "QUIC Security", VLESSGlobal.QUIC, s => server.QUICSecure = s, server.QUICSecure);
|
||||
CreateTextBox("QUICSecret", "QUIC Secret", s => true, s => server.QUICSecret = s, server.QUICSecret);
|
||||
CreateComboBox("UseMux",
|
||||
"Use Mux",
|
||||
new List<string> {"", "true", "false"},
|
||||
s => server.UseMux = s switch
|
||||
{
|
||||
"" => null,
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => null
|
||||
},
|
||||
s => server.UseMux = s switch {"" => null, "true" => true, "false" => false, _ => null},
|
||||
server.UseMux?.ToString().ToLower() ?? "");
|
||||
CreateComboBox("TLSSecure", "TLS Secure",
|
||||
VLESSGlobal.TLSSecure,
|
||||
s => server.TLSSecureType = s,
|
||||
server.TLSSecureType);
|
||||
|
||||
CreateComboBox("TLSSecure", "TLS Secure", VLESSGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);
|
||||
}
|
||||
|
||||
protected override string TypeName { get; } = "VLESS";
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,13 @@ namespace Netch.Servers.VLESS
|
||||
public class VLESSUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 2;
|
||||
|
||||
public string TypeName { get; } = "VLESS";
|
||||
|
||||
public string FullName { get; } = "VLESS";
|
||||
|
||||
public string ShortName { get; } = "VL";
|
||||
|
||||
public string[] UriScheme { get; } = {"vless"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
|
||||
@@ -9,58 +9,29 @@ namespace Netch.Servers.VMess.Form
|
||||
{
|
||||
server ??= new VMess();
|
||||
Server = server;
|
||||
CreateTextBox("UserId", "User ID",
|
||||
s => true,
|
||||
s => server.UserID = s,
|
||||
server.UserID);
|
||||
CreateTextBox("AlterId", "Alter ID",
|
||||
s => int.TryParse(s, out _),
|
||||
s => server.AlterID = int.Parse(s),
|
||||
server.AlterID.ToString(),
|
||||
76);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method",
|
||||
VMessGlobal.EncryptMethods,
|
||||
s => server.EncryptMethod = s,
|
||||
server.EncryptMethod);
|
||||
CreateComboBox("TransferProtocol", "Transfer Protocol",
|
||||
CreateTextBox("UserId", "User ID", s => true, s => server.UserID = s, server.UserID);
|
||||
CreateTextBox("AlterId", "Alter ID", s => int.TryParse(s, out _), s => server.AlterID = int.Parse(s), server.AlterID.ToString(), 76);
|
||||
CreateComboBox("EncryptMethod", "Encrypt Method", VMessGlobal.EncryptMethods, s => server.EncryptMethod = s, server.EncryptMethod);
|
||||
CreateComboBox("TransferProtocol",
|
||||
"Transfer Protocol",
|
||||
VMessGlobal.TransferProtocols,
|
||||
s => server.TransferProtocol = s,
|
||||
server.TransferProtocol);
|
||||
CreateComboBox("FakeType", "Fake Type",
|
||||
VMessGlobal.FakeTypes,
|
||||
s => server.FakeType = s,
|
||||
server.FakeType);
|
||||
CreateTextBox("Host", "Host",
|
||||
s => true,
|
||||
s => server.Host = s,
|
||||
server.Host);
|
||||
CreateTextBox("Path", "Path",
|
||||
s => true,
|
||||
s => server.Path = s,
|
||||
server.Path);
|
||||
CreateComboBox("QUICSecurity", "QUIC Security",
|
||||
VMessGlobal.QUIC,
|
||||
s => server.QUICSecure = s,
|
||||
server.QUICSecure);
|
||||
CreateTextBox("QUICSecret", "QUIC Secret",
|
||||
s => true,
|
||||
s => server.QUICSecret = s,
|
||||
server.QUICSecret);
|
||||
CreateComboBox("UseMux", "Use Mux",
|
||||
|
||||
CreateComboBox("FakeType", "Fake Type", VMessGlobal.FakeTypes, s => server.FakeType = s, server.FakeType);
|
||||
CreateTextBox("Host", "Host", s => true, s => server.Host = s, server.Host);
|
||||
CreateTextBox("Path", "Path", s => true, s => server.Path = s, server.Path);
|
||||
CreateComboBox("QUICSecurity", "QUIC Security", VMessGlobal.QUIC, s => server.QUICSecure = s, server.QUICSecure);
|
||||
CreateTextBox("QUICSecret", "QUIC Secret", s => true, s => server.QUICSecret = s, server.QUICSecret);
|
||||
CreateComboBox("UseMux",
|
||||
"Use Mux",
|
||||
new List<string> {"", "true", "false"},
|
||||
s => server.UseMux = s switch
|
||||
{
|
||||
"" => null,
|
||||
"true" => true,
|
||||
"false" => false,
|
||||
_ => null
|
||||
},
|
||||
s => server.UseMux = s switch {"" => null, "true" => true, "false" => false, _ => null},
|
||||
server.UseMux?.ToString().ToLower() ?? "");
|
||||
CreateComboBox("TLSSecure", "TLS Secure",
|
||||
VMessGlobal.TLSSecure,
|
||||
s => server.TLSSecureType = s,
|
||||
server.TLSSecureType);
|
||||
|
||||
CreateComboBox("TLSSecure", "TLS Secure", VMessGlobal.TLSSecure, s => server.TLSSecureType = s, server.TLSSecureType);
|
||||
}
|
||||
|
||||
protected override string TypeName { get; } = "VMess";
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ namespace Netch.Servers.VMess
|
||||
public class VMess : Server
|
||||
{
|
||||
private string _tlsSecureType = VMessGlobal.TLSSecure[0];
|
||||
|
||||
public VMess()
|
||||
{
|
||||
Type = "VMess";
|
||||
@@ -66,6 +67,7 @@ namespace Netch.Servers.VMess
|
||||
{
|
||||
if (value == "")
|
||||
value = "none";
|
||||
|
||||
_tlsSecureType = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,13 @@ namespace Netch.Servers.VMess
|
||||
public class VMessUtil : IServerUtil
|
||||
{
|
||||
public ushort Priority { get; } = 3;
|
||||
|
||||
public string TypeName { get; } = "VMess";
|
||||
|
||||
public string FullName { get; } = "VMess";
|
||||
|
||||
public string ShortName { get; } = "V2";
|
||||
|
||||
public string[] UriScheme { get; } = {"vmess"};
|
||||
|
||||
public Server ParseJObject(in JObject j)
|
||||
@@ -24,6 +28,7 @@ namespace Netch.Servers.VMess
|
||||
var server = j.ToObject<VMess>();
|
||||
if (server == null)
|
||||
return null;
|
||||
|
||||
string quic;
|
||||
if ((quic = j.GetValue("QUIC")?.ToString()) != null)
|
||||
server.QUICSecure = quic;
|
||||
@@ -61,6 +66,7 @@ namespace Netch.Servers.VMess
|
||||
path = server.Path,
|
||||
tls = server.TLSSecureType
|
||||
});
|
||||
|
||||
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace Netch.Updater
|
||||
FileName = temp7za,
|
||||
Arguments = argument.ToString()
|
||||
});
|
||||
|
||||
process?.WaitForExit();
|
||||
return process?.ExitCode ?? 2;
|
||||
}
|
||||
@@ -119,6 +120,7 @@ namespace Netch.Updater
|
||||
foreach (var dir in Directory.GetDirectories(sourceDirName, "*", SearchOption.AllDirectories))
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
foreach (var f in Directory.GetFiles(sourceDirName, "*", SearchOption.AllDirectories))
|
||||
try
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Netch.Utils
|
||||
public static TraceEventSession tSession;
|
||||
|
||||
private static readonly string[] Suffix = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
|
||||
|
||||
/// <summary>
|
||||
/// 计算流量
|
||||
/// </summary>
|
||||
@@ -31,9 +32,11 @@ namespace Netch.Utils
|
||||
{
|
||||
if (level >= 6) // Suffix.Length - 1
|
||||
break;
|
||||
|
||||
level++;
|
||||
size = (size ?? d) / step;
|
||||
}
|
||||
|
||||
return $@"{size ?? 0:0.##} {Suffix[level]}";
|
||||
}
|
||||
|
||||
@@ -60,6 +63,7 @@ namespace Netch.Utils
|
||||
case Guard instanceController:
|
||||
if (instanceController.Instance != null)
|
||||
instances.Add(instanceController.Instance);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -81,8 +85,7 @@ namespace Netch.Utils
|
||||
|
||||
var processList = instances.Select(instance => instance.Id).ToList();
|
||||
|
||||
Logging.Info("流量统计进程:" + string.Join(",",
|
||||
instances.Select(instance => $"({instance.Id})" + instance.ProcessName).ToArray()));
|
||||
Logging.Info("流量统计进程:" + string.Join(",", instances.Select(instance => $"({instance.Id})" + instance.ProcessName).ToArray()));
|
||||
|
||||
received = 0;
|
||||
|
||||
@@ -101,23 +104,21 @@ namespace Netch.Utils
|
||||
tSession.Source.Kernel.TcpIpRecv += data =>
|
||||
{
|
||||
if (processList.Contains(data.ProcessID))
|
||||
{
|
||||
lock (counterLock)
|
||||
received += (ulong) data.size;
|
||||
|
||||
// Debug.WriteLine($"TcpIpRecv: {ToByteSize(data.size)}");
|
||||
}
|
||||
// Debug.WriteLine($"TcpIpRecv: {ToByteSize(data.size)}");
|
||||
};
|
||||
|
||||
tSession.Source.Kernel.UdpIpRecv += data =>
|
||||
{
|
||||
if (processList.Contains(data.ProcessID))
|
||||
{
|
||||
lock (counterLock)
|
||||
received += (ulong) data.size;
|
||||
|
||||
// Debug.WriteLine($"UdpIpRecv: {ToByteSize(data.size)}");
|
||||
}
|
||||
// Debug.WriteLine($"UdpIpRecv: {ToByteSize(data.size)}");
|
||||
};
|
||||
|
||||
tSession.Source.Process();
|
||||
});
|
||||
|
||||
@@ -125,9 +126,7 @@ namespace Netch.Utils
|
||||
{
|
||||
Task.Delay(1000).Wait();
|
||||
lock (counterLock)
|
||||
{
|
||||
Global.MainForm.OnBandwidthUpdated(received);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,8 @@ namespace Netch.Utils
|
||||
}
|
||||
|
||||
if (settingJObject?["Profiles"] != null && Global.Settings.Profiles.Any() && settingJObject["Profiles"].First()?["Index"] == null)
|
||||
{
|
||||
foreach (var profile in Global.Settings.Profiles)
|
||||
{
|
||||
profile.Index = Global.Settings.Profiles.IndexOf(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
@@ -67,19 +63,15 @@ namespace Netch.Utils
|
||||
public static void Save()
|
||||
{
|
||||
if (!Directory.Exists(DATA_DIR))
|
||||
{
|
||||
Directory.CreateDirectory(DATA_DIR);
|
||||
}
|
||||
|
||||
File.WriteAllText(SETTINGS_JSON,
|
||||
JsonConvert.SerializeObject(
|
||||
Global.Settings,
|
||||
JsonConvert.SerializeObject(Global.Settings,
|
||||
Formatting.Indented,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
}
|
||||
));
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,55 +12,12 @@ namespace Netch.Utils
|
||||
/// <summary>
|
||||
/// 缓存
|
||||
/// </summary>
|
||||
public static Hashtable Cache = new Hashtable();
|
||||
public static Hashtable Cache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 查询
|
||||
/// </summary>
|
||||
/// <param name="hostname">主机名</param>
|
||||
/// <returns></returns>
|
||||
public static IPAddress Lookup(string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Cache.Contains(hostname))
|
||||
{
|
||||
return Cache[hostname] as IPAddress;
|
||||
}
|
||||
|
||||
var task = Dns.GetHostAddressesAsync(hostname);
|
||||
if (!task.Wait(1000))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (task.Result.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Cache.Add(hostname, task.Result[0]);
|
||||
|
||||
return task.Result[0];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static RegistryKey AdapterRegistry(bool write = false)
|
||||
{
|
||||
if (Global.Outbound.Adapter == null)
|
||||
Utils.SearchOutboundAdapter();
|
||||
return Registry.LocalMachine.OpenSubKey(
|
||||
$@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Global.Outbound.Adapter.Id}", write);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出口网卡 DNS
|
||||
/// <para></para>
|
||||
/// 依赖 <see cref="Global.Outbound.Adapter"/>
|
||||
/// 出口网卡 DNS
|
||||
/// <para></para>
|
||||
/// 依赖 <see cref="Global.Outbound.Adapter" />
|
||||
/// </summary>
|
||||
public static string OutboundDNS
|
||||
{
|
||||
@@ -78,6 +35,44 @@ namespace Netch.Utils
|
||||
set => AdapterRegistry(true).SetValue("NameServer", value, RegistryValueKind.String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询
|
||||
/// </summary>
|
||||
/// <param name="hostname">主机名</param>
|
||||
/// <returns></returns>
|
||||
public static IPAddress Lookup(string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Cache.Contains(hostname))
|
||||
return Cache[hostname] as IPAddress;
|
||||
|
||||
var task = Dns.GetHostAddressesAsync(hostname);
|
||||
if (!task.Wait(1000))
|
||||
return null;
|
||||
|
||||
if (task.Result.Length == 0)
|
||||
return null;
|
||||
|
||||
Cache.Add(hostname, task.Result[0]);
|
||||
|
||||
return task.Result[0];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static RegistryKey AdapterRegistry(bool write = false)
|
||||
{
|
||||
if (Global.Outbound.Adapter == null)
|
||||
Utils.SearchOutboundAdapter();
|
||||
|
||||
return Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Global.Outbound.Adapter.Id}",
|
||||
write);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Split(string dns)
|
||||
{
|
||||
return dns.Split(',').Where(ip => !string.IsNullOrWhiteSpace(ip)).Select(ip => ip.Trim());
|
||||
@@ -87,9 +82,7 @@ namespace Netch.Utils
|
||||
{
|
||||
result = Split(value).ToArray();
|
||||
|
||||
return maxCount == 0 || result.Count() <= maxCount
|
||||
&&
|
||||
result.All(ip => IPAddress.TryParse(ip, out _));
|
||||
return maxCount == 0 || result.Count() <= maxCount && result.All(ip => IPAddress.TryParse(ip, out _));
|
||||
}
|
||||
|
||||
public static string Join(IEnumerable<string> dns)
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (rule.ApplicationName.StartsWith(Global.NetchDir))
|
||||
return;
|
||||
|
||||
RemoveNetchFwRules();
|
||||
}
|
||||
|
||||
@@ -78,13 +79,11 @@ namespace Netch.Utils
|
||||
|
||||
private static void AddFwRule(string ruleName, string exeFullPath)
|
||||
{
|
||||
var rule = new FirewallWASRule(
|
||||
ruleName,
|
||||
var rule = new FirewallWASRule(ruleName,
|
||||
exeFullPath,
|
||||
FirewallAction.Allow,
|
||||
FirewallDirection.Inbound,
|
||||
FirewallProfiles.Private | FirewallProfiles.Public | FirewallProfiles.Domain
|
||||
);
|
||||
FirewallProfiles.Private | FirewallProfiles.Public | FirewallProfiles.Domain);
|
||||
|
||||
FirewallManager.Instance.Rules.Add(rule);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
public class HttpWebServer
|
||||
{
|
||||
private HttpListener _listener;
|
||||
private Func<HttpListenerRequest, string> _responderMethod;
|
||||
private readonly Func<HttpListenerRequest, string> _responderMethod;
|
||||
|
||||
public HttpWebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
|
||||
{
|
||||
@@ -17,8 +17,7 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
_listener = new HttpListener();
|
||||
|
||||
if (!HttpListener.IsSupported)
|
||||
throw new NotSupportedException(
|
||||
"Needs Windows XP SP2, Server 2003 or later.");
|
||||
throw new NotSupportedException("Needs Windows XP SP2, Server 2003 or later.");
|
||||
|
||||
// URI prefixes are required, for example
|
||||
// "http://localhost:8080/index/".
|
||||
@@ -29,7 +28,7 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
if (method == null)
|
||||
throw new ArgumentException("method");
|
||||
|
||||
foreach (string s in prefixes)
|
||||
foreach (var s in prefixes)
|
||||
_listener.Prefixes.Add(s);
|
||||
|
||||
_responderMethod = method;
|
||||
@@ -41,42 +40,40 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
}
|
||||
}
|
||||
|
||||
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
|
||||
: this(prefixes, method)
|
||||
public HttpWebServer(Func<HttpListenerRequest, string> method, params string[] prefixes) : this(prefixes, method)
|
||||
{
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem((o) =>
|
||||
ThreadPool.QueueUserWorkItem(o =>
|
||||
{
|
||||
Logging.Info("Webserver running...");
|
||||
try
|
||||
{
|
||||
while (_listener.IsListening)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem((c) =>
|
||||
{
|
||||
var ctx = c as HttpListenerContext;
|
||||
try
|
||||
ThreadPool.QueueUserWorkItem(c =>
|
||||
{
|
||||
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());
|
||||
}
|
||||
var ctx = c as HttpListenerContext;
|
||||
try
|
||||
{
|
||||
var rstr = _responderMethod(ctx.Request);
|
||||
var 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)
|
||||
{
|
||||
|
||||
@@ -9,37 +9,35 @@ using WindowsProxy;
|
||||
namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供PAC功能支持
|
||||
/// 提供PAC功能支持
|
||||
/// </summary>
|
||||
class PACServerHandle
|
||||
internal class PACServerHandle
|
||||
{
|
||||
private static Hashtable httpWebServer = new Hashtable();
|
||||
private static Hashtable pacList = new Hashtable();
|
||||
private static readonly Hashtable httpWebServer = new();
|
||||
private static readonly Hashtable pacList = new();
|
||||
|
||||
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);
|
||||
var prefixes = string.Format("http://{0}:{1}/pac/", address, Global.Settings.Pac_Port);
|
||||
|
||||
HttpWebServer ws = new HttpWebServer(SendResponse, prefixes);
|
||||
var 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()) + "");
|
||||
@@ -55,12 +53,11 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] arrAddress = request.UserHostAddress.Split(':');
|
||||
string address = "127.0.0.1";
|
||||
var arrAddress = request.UserHostAddress.Split(':');
|
||||
var address = "127.0.0.1";
|
||||
if (arrAddress.Length > 0)
|
||||
{
|
||||
address = arrAddress[0];
|
||||
}
|
||||
|
||||
return pacList[address].ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -75,14 +72,14 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
try
|
||||
{
|
||||
if (httpWebServer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var key in httpWebServer.Keys)
|
||||
{
|
||||
Logging.Info("Webserver Stop " + key.ToString());
|
||||
((HttpWebServer)httpWebServer[key]).Stop();
|
||||
Logging.Info("Webserver Stop " + key);
|
||||
((HttpWebServer) httpWebServer[key]).Stop();
|
||||
}
|
||||
|
||||
httpWebServer.Clear();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -95,30 +92,31 @@ namespace Netch.Utils.HttpProxyHandler
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> lstProxy = new List<string>();
|
||||
var 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 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地址
|
||||
/// 获取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"));
|
||||
var pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port, DateTime.Now.ToString("yyyyMMddHHmmssfff"));
|
||||
|
||||
return pacUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ namespace Netch.Utils
|
||||
{
|
||||
public const string LogFile = "logging\\application.log";
|
||||
|
||||
private static readonly object FileLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
@@ -35,14 +37,10 @@ namespace Netch.Utils
|
||||
Write(text, LogLevel.ERROR);
|
||||
}
|
||||
|
||||
private static readonly object FileLock = new object();
|
||||
|
||||
private static void Write(string text, LogLevel logLevel)
|
||||
{
|
||||
lock (FileLock)
|
||||
{
|
||||
File.AppendAllText(LogFile, $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Global.EOF}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,12 @@ namespace Netch.Utils
|
||||
{
|
||||
return fullName.Substring(ModeDirectory.Length);
|
||||
}
|
||||
|
||||
public static string GetFullPath(string relativeName)
|
||||
{
|
||||
return Path.Combine(ModeDirectory, relativeName);
|
||||
}
|
||||
|
||||
public static string GetFullPath(Mode mode)
|
||||
{
|
||||
return Path.Combine(ModeDirectory, mode.RelativePath);
|
||||
@@ -35,7 +37,8 @@ namespace Netch.Utils
|
||||
{
|
||||
Global.Modes.Clear();
|
||||
|
||||
if (!Directory.Exists(MODE_DIR)) return;
|
||||
if (!Directory.Exists(MODE_DIR))
|
||||
return;
|
||||
|
||||
var stack = new Stack<string>();
|
||||
stack.Push(MODE_DIR);
|
||||
@@ -64,7 +67,8 @@ namespace Netch.Utils
|
||||
var mode = new Mode(fullName);
|
||||
|
||||
var content = File.ReadAllLines(fullName);
|
||||
if (content.Length == 0) return;
|
||||
if (content.Length == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < content.Length; i++)
|
||||
{
|
||||
@@ -74,6 +78,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (text.First() != '#')
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var splited = text.Substring(1).Split(',').Select(s => s.Trim()).ToArray();
|
||||
@@ -125,15 +130,15 @@ namespace Netch.Utils
|
||||
public static bool SkipServerController(Server server, Mode mode)
|
||||
{
|
||||
return mode.Type switch
|
||||
{
|
||||
0 => server switch
|
||||
{
|
||||
Socks5 => true,
|
||||
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS => true,
|
||||
_ => false
|
||||
},
|
||||
_ => false
|
||||
};
|
||||
{
|
||||
0 => server switch
|
||||
{
|
||||
Socks5 => true,
|
||||
Shadowsocks shadowsocks when !shadowsocks.HasPlugin() && Global.Settings.RedirectorSS => true,
|
||||
_ => false
|
||||
},
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
public static IModeController GetModeControllerByType(int type, out ushort? port, out string portName, out PortType portType)
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Netch.Utils
|
||||
PortHelper.CheckPort(Global.Settings.UDPSocketPort, PortType.UDP);
|
||||
if (i != tryLimit)
|
||||
Configuration.Save();
|
||||
|
||||
break;
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -40,10 +40,13 @@ namespace Netch.Utils
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
|
||||
process.OutputDataReceived += (s, e) =>
|
||||
{
|
||||
if (e.Data != null) lines.Add(e.Data);
|
||||
if (e.Data != null)
|
||||
lines.Add(e.Data);
|
||||
};
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.WaitForExit();
|
||||
@@ -86,6 +89,7 @@ namespace Netch.Utils
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckPortInUse(ushort port, PortType type)
|
||||
{
|
||||
switch (type)
|
||||
@@ -97,15 +101,18 @@ namespace Netch.Utils
|
||||
case PortType.TCP:
|
||||
if (NetInfo.GetActiveTcpListeners().Any(ipEndPoint => ipEndPoint.Port == port))
|
||||
throw new PortInUseException();
|
||||
|
||||
break;
|
||||
case PortType.UDP:
|
||||
if (NetInfo.GetActiveUdpListeners().Any(ipEndPoint => ipEndPoint.Port == port))
|
||||
throw new PortInUseException();
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查端口是否是保留端口
|
||||
/// </summary>
|
||||
@@ -120,10 +127,12 @@ namespace Netch.Utils
|
||||
case PortType.TCP:
|
||||
if (TCPReservedRanges.Any(range => range.InRange(port)))
|
||||
throw new PortReservedException();
|
||||
|
||||
break;
|
||||
case PortType.UDP:
|
||||
if (UDPReservedRanges.Any(range => range.InRange(port)))
|
||||
throw new PortReservedException();
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||
@@ -166,15 +175,18 @@ namespace Netch.Utils
|
||||
public PortInUseException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PortInUseException()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class PortReservedException : Exception
|
||||
{
|
||||
public PortReservedException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PortReservedException()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -13,7 +13,10 @@ namespace Netch.Utils
|
||||
{
|
||||
static ServerHelper()
|
||||
{
|
||||
var serversUtilsTypes = Assembly.GetExecutingAssembly().GetExportedTypes().Where(type => type.GetInterfaces().Contains(typeof(IServerUtil)));
|
||||
var serversUtilsTypes = Assembly.GetExecutingAssembly()
|
||||
.GetExportedTypes()
|
||||
.Where(type => type.GetInterfaces().Contains(typeof(IServerUtil)));
|
||||
|
||||
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil) Activator.CreateInstance(t)).OrderBy(util => util.Priority);
|
||||
}
|
||||
|
||||
@@ -25,6 +28,7 @@ namespace Netch.Utils
|
||||
private static bool _mux;
|
||||
|
||||
public static readonly Range Range = new(0, int.MaxValue / 1000);
|
||||
|
||||
static DelayTestHelper()
|
||||
{
|
||||
Timer = new Timer
|
||||
@@ -43,6 +47,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (!ValueIsEnabled(Global.Settings.DetectionTick))
|
||||
return;
|
||||
|
||||
Timer.Enabled = value;
|
||||
}
|
||||
}
|
||||
@@ -53,17 +58,18 @@ namespace Netch.Utils
|
||||
{
|
||||
return value != 0 && Range.InRange(value);
|
||||
}
|
||||
|
||||
public static event EventHandler TestDelayFinished;
|
||||
|
||||
public static void TestAllDelay()
|
||||
{
|
||||
if (_mux)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_mux = true;
|
||||
Parallel.ForEach(Global.Settings.Server, new ParallelOptions {MaxDegreeOfParallelism = 16},
|
||||
server => { server.Test(); });
|
||||
Parallel.ForEach(Global.Settings.Server, new ParallelOptions {MaxDegreeOfParallelism = 16}, server => { server.Test(); });
|
||||
_mux = false;
|
||||
TestDelayFinished?.Invoke(null, new EventArgs());
|
||||
}
|
||||
@@ -108,6 +114,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
return null;
|
||||
|
||||
return ServerUtils.FirstOrDefault(i => (i.TypeName ?? "").Equals(typeName));
|
||||
}
|
||||
|
||||
@@ -115,6 +122,7 @@ namespace Netch.Utils
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullName))
|
||||
return null;
|
||||
|
||||
return ServerUtils.FirstOrDefault(i => (i.FullName ?? "").Equals(fullName));
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +33,17 @@ namespace Netch.Utils
|
||||
|
||||
try
|
||||
{
|
||||
list.AddRange(JsonConvert.DeserializeObject<List<ShadowsocksConfig>>(text).Select(server => new Shadowsocks
|
||||
{
|
||||
Hostname = server.server,
|
||||
Port = server.server_port,
|
||||
EncryptMethod = server.method,
|
||||
Password = server.password,
|
||||
Remark = server.remarks,
|
||||
Plugin = server.plugin,
|
||||
PluginOption = server.plugin_opts
|
||||
}));
|
||||
list.AddRange(JsonConvert.DeserializeObject<List<ShadowsocksConfig>>(text)
|
||||
.Select(server => new Shadowsocks
|
||||
{
|
||||
Hostname = server.server,
|
||||
Port = server.server_port,
|
||||
EncryptMethod = server.method,
|
||||
Password = server.password,
|
||||
Remark = server.remarks,
|
||||
Plugin = server.plugin,
|
||||
PluginOption = server.plugin_opts
|
||||
}));
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
@@ -98,6 +99,7 @@ namespace Netch.Utils
|
||||
var endIndex = text.IndexOf("://", StringComparison.Ordinal);
|
||||
if (endIndex == -1)
|
||||
throw new UriFormatException("Text is not a URI");
|
||||
|
||||
return text.Substring(0, endIndex);
|
||||
}
|
||||
|
||||
@@ -131,7 +133,9 @@ namespace Netch.Utils
|
||||
public static string GetNetchLink(Server s)
|
||||
{
|
||||
var server = (Server) s.Clone();
|
||||
return "Netch://" + URLSafeBase64Encode(JsonConvert.SerializeObject(server, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
|
||||
return "Netch://" +
|
||||
URLSafeBase64Encode(JsonConvert.SerializeObject(server,
|
||||
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
|
||||
}
|
||||
|
||||
#region Utils
|
||||
@@ -143,7 +147,8 @@ namespace Netch.Utils
|
||||
/// <returns>解码后的字符串</returns>
|
||||
public static string URLSafeBase64Decode(string text)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(text.Replace("-", "+").Replace("_", "/").PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
|
||||
return Encoding.UTF8.GetString(
|
||||
Convert.FromBase64String(text.Replace("-", "+").Replace("_", "/").PadRight(text.Length + (4 - text.Length % 4) % 4, '=')));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -163,6 +168,7 @@ namespace Netch.Utils
|
||||
var startIndex = 0;
|
||||
while (remark.Length > startIndex + 1 && remark[startIndex] == emojiBytes[0] && remark[startIndex + 1] == emojiBytes[1])
|
||||
startIndex += 4;
|
||||
|
||||
return Encoding.UTF8.GetString(remark.Skip(startIndex).ToArray()).Trim();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ namespace Netch.Utils
|
||||
|
||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
if (s.IsNullOrEmpty())
|
||||
return false;
|
||||
|
||||
return chars.Contains(s[0]);
|
||||
}
|
||||
|
||||
@@ -27,10 +29,12 @@ namespace Netch.Utils
|
||||
{
|
||||
foreach (var c in value)
|
||||
{
|
||||
if (char.IsWhiteSpace(c)) continue;
|
||||
if (char.IsWhiteSpace(c))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -39,7 +43,9 @@ namespace Netch.Utils
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.IsWhiteSpace()) continue;
|
||||
if (line.IsWhiteSpace())
|
||||
continue;
|
||||
|
||||
yield return line;
|
||||
}
|
||||
}
|
||||
@@ -51,8 +57,10 @@ namespace Netch.Utils
|
||||
{
|
||||
if (new[] {'\\', '(', ')', '[', ']', '.'}.Any(s => s == t))
|
||||
sb.Append(@"\");
|
||||
|
||||
sb.Append(t);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,11 @@ namespace Netch.Utils
|
||||
{
|
||||
public static class Subscription
|
||||
{
|
||||
private static readonly object ServerLock = new object();
|
||||
private static readonly object ServerLock = new();
|
||||
|
||||
public static async Task UpdateServersAsync(string proxyServer = default)
|
||||
{
|
||||
await Task.WhenAll(
|
||||
Global.Settings.SubscribeLink.Select(item =>
|
||||
Task.Run(() => UpdateServer(item, proxyServer))
|
||||
).ToArray()
|
||||
);
|
||||
await Task.WhenAll(Global.Settings.SubscribeLink.Select(item => Task.Run(() => UpdateServer(item, proxyServer))).ToArray());
|
||||
}
|
||||
|
||||
public static void UpdateServer(SubscribeLink item, string proxyServer)
|
||||
@@ -25,13 +21,15 @@ namespace Netch.Utils
|
||||
try
|
||||
{
|
||||
if (!item.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var request = WebUtil.CreateRequest(item.Link);
|
||||
|
||||
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;
|
||||
if (!string.IsNullOrEmpty(proxyServer)) request.Proxy = new WebProxy(proxyServer);
|
||||
if (!string.IsNullOrEmpty(item.UserAgent))
|
||||
request.UserAgent = item.UserAgent;
|
||||
|
||||
if (!string.IsNullOrEmpty(proxyServer))
|
||||
request.Proxy = new WebProxy(proxyServer);
|
||||
|
||||
List<Server> servers;
|
||||
|
||||
@@ -41,7 +39,8 @@ namespace Netch.Utils
|
||||
else
|
||||
throw new Exception($"{item.Remark} Response Status Code: {rep.StatusCode}");
|
||||
|
||||
foreach (var server in servers) server.Group = item.Remark;
|
||||
foreach (var server in servers)
|
||||
server.Group = item.Remark;
|
||||
|
||||
lock (ServerLock)
|
||||
{
|
||||
|
||||
@@ -23,18 +23,14 @@ namespace Netch.Utils
|
||||
var adaptersRegistry = Registry.LocalMachine.OpenSubKey(ADAPTER_KEY);
|
||||
|
||||
foreach (var adapterRegistryName in adaptersRegistry.GetSubKeyNames())
|
||||
{
|
||||
if (adapterRegistryName != "Configuration" && adapterRegistryName != "Properties")
|
||||
{
|
||||
var adapterRegistry = adaptersRegistry.OpenSubKey(adapterRegistryName);
|
||||
|
||||
var adapterComponentId = adapterRegistry.GetValue("ComponentId", "").ToString();
|
||||
if (adapterComponentId == TUNTAP_COMPONENT_ID_0901 || adapterComponentId == TUNTAP_COMPONENT_ID_0801)
|
||||
{
|
||||
return adapterRegistry.GetValue("NetCfgInstanceId", "").ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -66,25 +62,29 @@ namespace Netch.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载tap网卡
|
||||
/// 卸载tap网卡
|
||||
/// </summary>
|
||||
public static void deltapall()
|
||||
{
|
||||
Logging.Info("卸载 TUN/TAP 适配器");
|
||||
var installProcess = new Process {StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "deltapall.bat")}};
|
||||
var installProcess = new Process
|
||||
{StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "deltapall.bat")}};
|
||||
|
||||
installProcess.Start();
|
||||
installProcess.WaitForExit();
|
||||
installProcess.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装tap网卡
|
||||
/// 安装tap网卡
|
||||
/// </summary>
|
||||
public static void addtap()
|
||||
{
|
||||
Logging.Info("安装 TUN/TAP 适配器");
|
||||
//安装Tap Driver
|
||||
var installProcess = new Process {StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "addtap.bat")}};
|
||||
var installProcess = new Process
|
||||
{StartInfo = {WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.Combine("bin/tap-driver", "addtap.bat")}};
|
||||
|
||||
installProcess.Start();
|
||||
installProcess.WaitForExit();
|
||||
installProcess.Close();
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Netch.Utils
|
||||
Arguments = path,
|
||||
UseShellExecute = true
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
@@ -140,8 +141,7 @@ namespace Netch.Utils
|
||||
public static void SearchOutboundAdapter(bool logging = true)
|
||||
{
|
||||
// 寻找出口适配器
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0),
|
||||
0, out var pRoute) != 0)
|
||||
if (IpHlpApi.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), 0, out var pRoute) != 0)
|
||||
{
|
||||
Logging.Error("GetBestRoute 搜索失败");
|
||||
throw new Exception("GetBestRoute 搜索失败");
|
||||
@@ -149,17 +149,19 @@ namespace Netch.Utils
|
||||
|
||||
Global.Outbound.Index = (int) pRoute.dwForwardIfIndex;
|
||||
// 根据 IP Index 寻找 出口适配器
|
||||
var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ =>
|
||||
{
|
||||
try
|
||||
var adapter = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.First(_ =>
|
||||
{
|
||||
return _.GetIPProperties().GetIPv4Properties().Index == Global.Outbound.Index;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
return _.GetIPProperties().GetIPv4Properties().Index == Global.Outbound.Index;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Global.Outbound.Adapter = adapter;
|
||||
Global.Outbound.Gateway = new IPAddress(pRoute.dwForwardNextHop.S_un_b);
|
||||
|
||||
@@ -186,7 +188,10 @@ namespace Netch.Utils
|
||||
if (e.Index < 0)
|
||||
return;
|
||||
|
||||
TextRenderer.DrawText(e.Graphics, cbx.Items[e.Index].ToString(), cbx.Font, e.Bounds,
|
||||
TextRenderer.DrawText(e.Graphics,
|
||||
cbx.Items[e.Index].ToString(),
|
||||
cbx.Font,
|
||||
e.Bounds,
|
||||
(e.State & DrawItemState.Selected) == DrawItemState.Selected ? SystemColors.HighlightText : cbx.ForeColor,
|
||||
TextFormatFlags.HorizontalCenter);
|
||||
}
|
||||
@@ -271,7 +276,9 @@ namespace Netch.Utils
|
||||
{
|
||||
case TextBox _:
|
||||
case ComboBox _:
|
||||
if (((Control) component).ForeColor != color) ((Control) component).ForeColor = color;
|
||||
if (((Control) component).ForeColor != color)
|
||||
((Control) component).ForeColor = color;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace Netch.Utils
|
||||
{
|
||||
public static class WebUtil
|
||||
{
|
||||
public const string DefaultUserAgent =
|
||||
@"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55";
|
||||
|
||||
static WebUtil()
|
||||
{
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
|
||||
}
|
||||
|
||||
public const string DefaultUserAgent =
|
||||
@"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55";
|
||||
|
||||
private static int DefaultGetTimeout => Global.Settings.RequestTimeout;
|
||||
|
||||
public static HttpWebRequest CreateRequest(string url, int? timeout = null, string userAgent = null)
|
||||
@@ -99,4 +99,4 @@ namespace Netch.Utils
|
||||
fileStream.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,8 @@ namespace Netch.Utils
|
||||
|
||||
var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
|
||||
|
||||
if (data == null) return;
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
Data = new Hashtable();
|
||||
foreach (var v in data)
|
||||
@@ -84,6 +85,7 @@ namespace Netch.Utils
|
||||
a.Append(Data.Contains(t) ? Data[t].ToString() : t);
|
||||
else
|
||||
a.Append(t);
|
||||
|
||||
return a.ToString();
|
||||
}
|
||||
|
||||
@@ -100,31 +102,34 @@ namespace Netch.Utils
|
||||
{
|
||||
var translateFile = new List<string> {"System", "zh-CN", "en-US"};
|
||||
|
||||
if (!Directory.Exists("i18n")) return translateFile;
|
||||
if (!Directory.Exists("i18n"))
|
||||
return translateFile;
|
||||
|
||||
translateFile.AddRange(Directory.GetFiles("i18n", "*").Select(fileName => fileName.Substring(5)));
|
||||
return translateFile;
|
||||
}
|
||||
|
||||
public static void TranslateForm(in Control c)
|
||||
{
|
||||
Utils.ComponentIterator(c, component =>
|
||||
{
|
||||
switch (component)
|
||||
Utils.ComponentIterator(c,
|
||||
component =>
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
break;
|
||||
case Control c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
case ToolStripItem c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
case ColumnHeader c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
}
|
||||
});
|
||||
switch (component)
|
||||
{
|
||||
case TextBoxBase _:
|
||||
case ListControl _:
|
||||
break;
|
||||
case Control c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
case ToolStripItem c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
case ColumnHeader c:
|
||||
c.Text = Translate(c.Text);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,4 @@ namespace Netch
|
||||
[DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
public static extern IntPtr GetForegroundWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user