This commit is contained in:
zmjack 2024-06-14 01:15:48 +08:00
parent 6bee3ea985
commit 8e36f87205
26 changed files with 1712 additions and 1727 deletions

View File

@ -1,5 +1,5 @@
namespace PortProxyGUI namespace PortProxyGUI;
{
partial class About partial class About
{ {
/// <summary> /// <summary>
@ -82,4 +82,3 @@
private System.Windows.Forms.Label label_version; private System.Windows.Forms.Label label_version;
private System.Windows.Forms.Label label_Star; private System.Windows.Forms.Label label_Star;
} }
}

View File

@ -2,8 +2,8 @@
using System.Diagnostics; using System.Diagnostics;
using System.Windows.Forms; using System.Windows.Forms;
namespace PortProxyGUI namespace PortProxyGUI;
{
public partial class About : Form public partial class About : Form
{ {
public readonly PortProxyGUI PortProxyGUI; public readonly PortProxyGUI PortProxyGUI;
@ -29,4 +29,3 @@ namespace PortProxyGUI
PortProxyGUI.AboutForm = null; PortProxyGUI.AboutForm = null;
} }
} }
}

View File

@ -3,12 +3,12 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public class AppConfig public class AppConfig
{ {
public Size MainWindowSize = new(720, 500); public Size MainWindowSize = new(720, 500);
public int[] PortProxyColumnWidths = new int[] { 24, 64, 140, 100, 140, 100, 100 }; public int[] PortProxyColumnWidths = [24, 64, 140, 100, 140, 100, 100];
private readonly Regex _intArrayRegex = new(@"^\[\s*(\d+)(?:\s*,\s*(\d+))*\s*\]$"); private readonly Regex _intArrayRegex = new(@"^\[\s*(\d+)(?:\s*,\s*(\d+))*\s*\]$");
@ -43,11 +43,10 @@ namespace PortProxyGUI.Data
#if NETCOREAPP3_0_OR_GREATER #if NETCOREAPP3_0_OR_GREATER
PortProxyColumnWidths = Array.Empty<int>(); PortProxyColumnWidths = Array.Empty<int>();
#else #else
PortProxyColumnWidths = new int[0]; PortProxyColumnWidths = [];
#endif #endif
} }
} }
} }
} }
}

View File

@ -5,8 +5,8 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public class ApplicationDbScope : SqliteScope<ApplicationDbScope> public class ApplicationDbScope : SqliteScope<ApplicationDbScope>
{ {
public static readonly string AppDbDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PortProxyGUI"); public static readonly string AppDbDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PortProxyGUI");
@ -110,4 +110,3 @@ namespace PortProxyGUI.Data
} }
} }
}

View File

@ -1,9 +1,8 @@
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public class Config public class Config
{ {
public string Item { get; set; } public string Item { get; set; }
public string Key { get; set; } public string Key { get; set; }
public string Value { get; set; } public string Value { get; set; }
} }
}

View File

@ -1,8 +1,7 @@
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public class Migration public class Migration
{ {
public string MigrationId { get; set; } public string MigrationId { get; set; }
public string ProductVersion { get; set; } public string ProductVersion { get; set; }
} }
}

View File

@ -1,8 +1,7 @@
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public struct MigrationKey public struct MigrationKey
{ {
public string MigrationId { get; set; } public string MigrationId { get; set; }
public string ProductVersion { get; set; } public string ProductVersion { get; set; }
} }
}

View File

@ -5,8 +5,8 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Windows.Forms; using System.Windows.Forms;
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public class MigrationUtil public class MigrationUtil
{ {
public ApplicationDbScope DbScope { get; private set; } public ApplicationDbScope DbScope { get; private set; }
@ -67,8 +67,8 @@ Would you like to download it now?", "Upgrade", MessageBoxButtons.YesNo, Message
public Dictionary<MigrationKey, string[]> History = new Dictionary<MigrationKey, string[]> public Dictionary<MigrationKey, string[]> History = new Dictionary<MigrationKey, string[]>
{ {
[new MigrationKey { MigrationId = "202103021542", ProductVersion = "1.1.0" }] = new[] [new MigrationKey { MigrationId = "202103021542", ProductVersion = "1.1.0" }] =
{ [
@"CREATE TABLE rules @"CREATE TABLE rules
( (
Id text PRIMARY KEY, Id text PRIMARY KEY,
@ -79,16 +79,16 @@ Would you like to download it now?", "Upgrade", MessageBoxButtons.YesNo, Message
ConnectPort integer ConnectPort integer
);", );",
"CREATE UNIQUE INDEX IX_Rules_Type_ListenOn_ListenPort ON Rules(Type, ListenOn, ListenPort);", "CREATE UNIQUE INDEX IX_Rules_Type_ListenOn_ListenPort ON Rules(Type, ListenOn, ListenPort);",
}, ],
[new MigrationKey { MigrationId = "202201172103", ProductVersion = "1.2.0" }] = new[] [new MigrationKey { MigrationId = "202201172103", ProductVersion = "1.2.0" }] =
{ [
"ALTER TABLE rules ADD Note text;", "ALTER TABLE rules ADD Note text;",
"ALTER TABLE rules ADD `Group` text;", "ALTER TABLE rules ADD `Group` text;",
}, ],
[new MigrationKey { MigrationId = "202202221635", ProductVersion = "1.3.0" }] = new[] [new MigrationKey { MigrationId = "202202221635", ProductVersion = "1.3.0" }] =
{ [
"ALTER TABLE rules RENAME TO rulesOld;", "ALTER TABLE rules RENAME TO rulesOld;",
"DROP INDEX IX_Rules_Type_ListenOn_ListenPort;", "DROP INDEX IX_Rules_Type_ListenOn_ListenPort;",
@ -106,10 +106,10 @@ Would you like to download it now?", "Upgrade", MessageBoxButtons.YesNo, Message
"INSERT INTO rules SELECT Id, Type, ListenOn, ListenPort, ConnectTo, ConnectPort, Note, `Group` FROM rulesOld;", "INSERT INTO rules SELECT Id, Type, ListenOn, ListenPort, ConnectTo, ConnectPort, Note, `Group` FROM rulesOld;",
"DROP TABLE rulesOld;", "DROP TABLE rulesOld;",
}, ],
[new MigrationKey { MigrationId = "202303092024", ProductVersion = "1.4.0" }] = new[] [new MigrationKey { MigrationId = "202303092024", ProductVersion = "1.4.0" }] =
{ [
@"CREATE TABLE configs ( @"CREATE TABLE configs (
Item text, Item text,
`Key` text, `Key` text,
@ -121,7 +121,6 @@ Would you like to download it now?", "Upgrade", MessageBoxButtons.YesNo, Message
"INSERT INTO configs ( Item, `Key`, Value ) VALUES ( 'MainWindow', 'Width', '720' );", "INSERT INTO configs ( Item, `Key`, Value ) VALUES ( 'MainWindow', 'Width', '720' );",
"INSERT INTO configs ( Item, `Key`, Value ) VALUES ( 'MainWindow', 'Height', '500' );", "INSERT INTO configs ( Item, `Key`, Value ) VALUES ( 'MainWindow', 'Height', '500' );",
"INSERT INTO configs ( Item, `Key`, Value ) VALUES ( 'PortProxy', 'ColumnWidths', '[24, 64, 140, 100, 140, 100, 100]' );", "INSERT INTO configs ( Item, `Key`, Value ) VALUES ( 'PortProxy', 'ColumnWidths', '[24, 64, 140, 100, 140, 100, 100]' );",
}, ],
}; };
} }
}

View File

@ -1,7 +1,7 @@
using System; using System;
namespace PortProxyGUI.Data namespace PortProxyGUI.Data;
{
public class Rule : IEquatable<Rule> public class Rule : IEquatable<Rule>
{ {
public string Id { get; set; } public string Id { get; set; }
@ -71,4 +71,3 @@ namespace PortProxyGUI.Data
return Equals(obj as Rule); return Equals(obj as Rule);
} }
} }
}

View File

@ -1,7 +1,7 @@
using System; using System;
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
[Flags] [Flags]
internal enum GenericRights : uint internal enum GenericRights : uint
{ {
@ -10,4 +10,3 @@ namespace PortProxyGUI.Native
GENERIC_EXECUTE = 0x20000000, GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000, GENERIC_ALL = 0x10000000,
} }
}

View File

@ -1,8 +1,8 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
internal class NativeMethods internal class NativeMethods
{ {
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
@ -30,4 +30,3 @@ namespace PortProxyGUI.Native
internal static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors); internal static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
} }
}

View File

@ -1,5 +1,5 @@
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
internal enum ScmRights : uint internal enum ScmRights : uint
{ {
SC_MANAGER_CONNECT = 0x0001, SC_MANAGER_CONNECT = 0x0001,
@ -18,4 +18,3 @@
| SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_QUERY_LOCK_STATUS
| SC_MANAGER_MODIFY_BOOT_CONFIG | SC_MANAGER_MODIFY_BOOT_CONFIG
} }
}

View File

@ -1,10 +1,9 @@
using System; using System;
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
[Flags] [Flags]
internal enum ServiceControls : uint internal enum ServiceControls : uint
{ {
SERVICE_CONTROL_PARAMCHANGE = 0x00000006, SERVICE_CONTROL_PARAMCHANGE = 0x00000006,
} }
}

View File

@ -1,7 +1,7 @@
using System; using System;
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
[Flags] [Flags]
internal enum ServiceRights : uint internal enum ServiceRights : uint
{ {
@ -26,4 +26,3 @@ namespace PortProxyGUI.Native
| SERVICE_INTERROGATE | SERVICE_INTERROGATE
| SERVICE_USER_DEFINED_CONTROL | SERVICE_USER_DEFINED_CONTROL
} }
}

View File

@ -1,5 +1,5 @@
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
internal enum ServiceState : int internal enum ServiceState : int
{ {
SERVICE_STOPPED = 0x00000001, SERVICE_STOPPED = 0x00000001,
@ -10,4 +10,3 @@
SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007, SERVICE_PAUSED = 0x00000007,
} }
}

View File

@ -1,7 +1,7 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct ServiceStatus internal struct ServiceStatus
{ {
@ -13,4 +13,3 @@ namespace PortProxyGUI.Native
public uint dwCheckPoint; public uint dwCheckPoint;
public uint dwWaitHint; public uint dwWaitHint;
} }
}

View File

@ -1,7 +1,6 @@
namespace PortProxyGUI.Native namespace PortProxyGUI.Native;
{
internal enum StandardRights : uint internal enum StandardRights : uint
{ {
STANDARD_RIGHTS_REQUIRED = 0x000F0000, STANDARD_RIGHTS_REQUIRED = 0x000F0000,
} }
}

View File

@ -1,5 +1,5 @@
namespace PortProxyGUI namespace PortProxyGUI;
{
partial class PortProxyGUI partial class PortProxyGUI
{ {
/// <summary> /// <summary>
@ -297,5 +297,4 @@
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel_Status; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel_Status;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel_ServiceNotRunning; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel_ServiceNotRunning;
} }
}

View File

@ -9,8 +9,8 @@ using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using static System.Windows.Forms.ListViewItem; using static System.Windows.Forms.ListViewItem;
namespace PortProxyGUI namespace PortProxyGUI;
{
public partial class PortProxyGUI : Form public partial class PortProxyGUI : Form
{ {
private readonly ListViewColumnSorter lvwColumnSorter = new ListViewColumnSorter(); private readonly ListViewColumnSorter lvwColumnSorter = new ListViewColumnSorter();
@ -87,7 +87,7 @@ namespace PortProxyGUI
try try
{ {
var rule = ParseRule(item); var rule = ParseRule(item);
PortPorxyUtil.AddOrUpdateProxy(rule); Util.AddOrUpdateProxy(rule);
} }
catch (NotSupportedException ex) catch (NotSupportedException ex)
{ {
@ -95,7 +95,7 @@ namespace PortProxyGUI
return; return;
} }
} }
PortPorxyUtil.ParamChange(); Util.ParamChange();
} }
private void DisableSelectedProxies() private void DisableSelectedProxies()
@ -108,7 +108,7 @@ namespace PortProxyGUI
try try
{ {
var rule = ParseRule(item); var rule = ParseRule(item);
PortPorxyUtil.DeleteProxy(rule); Util.DeleteProxy(rule);
} }
catch (NotSupportedException ex) catch (NotSupportedException ex)
{ {
@ -116,7 +116,7 @@ namespace PortProxyGUI
return; return;
} }
} }
PortPorxyUtil.ParamChange(); Util.ParamChange();
} }
private void DeleteSelectedProxies() private void DeleteSelectedProxies()
@ -199,7 +199,7 @@ namespace PortProxyGUI
public void RefreshProxyList() public void RefreshProxyList()
{ {
var proxies = PortPorxyUtil.GetProxies(); var proxies = Util.GetProxies();
var rules = Program.Database.Rules.ToArray(); var rules = Program.Database.Rules.ToArray();
foreach (var proxy in proxies) foreach (var proxy in proxies)
{ {
@ -223,7 +223,7 @@ namespace PortProxyGUI
InitProxyItems(rules, proxies); InitProxyItems(rules, proxies);
// CheckServiceStatus // CheckServiceStatus
toolStripStatusLabel_ServiceNotRunning.Visible = !PortPorxyUtil.IsServiceRunning(); toolStripStatusLabel_ServiceNotRunning.Visible = !Util.IsServiceRunning();
} }
private void contextMenuStrip_RightClick_MouseClick(object sender, MouseEventArgs e) private void contextMenuStrip_RightClick_MouseClick(object sender, MouseEventArgs e)
@ -402,8 +402,7 @@ namespace PortProxyGUI
private void toolStripStatusLabel_ServiceNotRunning_Click(object sender, EventArgs e) private void toolStripStatusLabel_ServiceNotRunning_Click(object sender, EventArgs e)
{ {
PortPorxyUtil.StartService(); Util.StartService();
toolStripStatusLabel_ServiceNotRunning.Visible = false; toolStripStatusLabel_ServiceNotRunning.Visible = false;
} }
} }
}

View File

@ -1,18 +1,28 @@
using PortProxyGUI.Data; using PortProxyGUI.Data;
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
namespace PortProxyGUI namespace PortProxyGUI;
{
static class Program static class Program
{ {
public static readonly ApplicationDbScope Database = ApplicationDbScope.FromFile( private static string GetPath(params string[] pathes)
Path.Combine( {
Path.Combine( if (!pathes.Any()) return string.Empty;
#if NET6_0_OR_GREATER || NET451_OR_GREATER
return Path.Combine(pathes);
#else
return pathes.Aggregate(Path.Combine);
#endif
}
public static ApplicationDbScope Database { get; } = ApplicationDbScope.FromFile(GetPath(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"PortProxyGUI" "PortProxyGUI",
), "config.db" "config.db"
)); ));
/// <summary> /// <summary>
@ -38,4 +48,3 @@ namespace PortProxyGUI
Application.Run(new PortProxyGUI()); Application.Run(new PortProxyGUI());
} }
} }
}

View File

@ -1,5 +1,5 @@
namespace PortProxyGUI namespace PortProxyGUI;
{
partial class SetProxy partial class SetProxy
{ {
/// <summary> /// <summary>
@ -181,4 +181,3 @@
private System.Windows.Forms.Label label_Group; private System.Windows.Forms.Label label_Group;
private System.Windows.Forms.ComboBox comboBox_Group; private System.Windows.Forms.ComboBox comboBox_Group;
} }
}

View File

@ -6,8 +6,8 @@ using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
namespace PortProxyGUI namespace PortProxyGUI;
{
public partial class SetProxy : Form public partial class SetProxy : Form
{ {
public readonly PortProxyGUI ParentWindow; public readonly PortProxyGUI ParentWindow;
@ -115,22 +115,22 @@ namespace PortProxyGUI
if (_updateMode) if (_updateMode)
{ {
var oldRule = Program.Database.GetRule(_itemRule.Type, _itemRule.ListenOn, _itemRule.ListenPort); var oldRule = Program.Database.GetRule(_itemRule.Type, _itemRule.ListenOn, _itemRule.ListenPort);
PortPorxyUtil.DeleteProxy(oldRule); Util.DeleteProxy(oldRule);
Program.Database.Remove(oldRule); Program.Database.Remove(oldRule);
PortPorxyUtil.AddOrUpdateProxy(rule); Util.AddOrUpdateProxy(rule);
Program.Database.Add(rule); Program.Database.Add(rule);
ParentWindow.UpdateListViewItem(_listViewItem, rule, 1); ParentWindow.UpdateListViewItem(_listViewItem, rule, 1);
} }
else else
{ {
PortPorxyUtil.AddOrUpdateProxy(rule); Util.AddOrUpdateProxy(rule);
Program.Database.Add(rule); Program.Database.Add(rule);
ParentWindow.RefreshProxyList(); ParentWindow.RefreshProxyList();
} }
PortPorxyUtil.ParamChange(); Util.ParamChange();
Close(); Close();
} }
@ -147,4 +147,3 @@ namespace PortProxyGUI
} }
} }
}

View File

@ -1,8 +1,8 @@
using System.Collections; using System.Collections;
using System.Windows.Forms; using System.Windows.Forms;
namespace PortProxyGUI.UI namespace PortProxyGUI.UI;
{
public class ListViewColumnSorter : IComparer public class ListViewColumnSorter : IComparer
{ {
/// <summary> /// <summary>
@ -108,4 +108,3 @@ namespace PortProxyGUI.UI
} }
} }
}

View File

@ -1,8 +1,8 @@
using PortProxyGUI.Native; using PortProxyGUI.Native;
using System; using System;
namespace PortProxyGUI.Utils namespace PortProxyGUI.Utils;
{
internal class DnsUtil internal class DnsUtil
{ {
public static void FlushCache() public static void FlushCache()
@ -12,4 +12,3 @@ namespace PortProxyGUI.Utils
} }
} }
}

View File

@ -1,149 +0,0 @@
using Microsoft.Win32;
using PortProxyGUI.Data;
using PortProxyGUI.Native;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PortProxyGUI.Utils
{
public static class PortPorxyUtil
{
internal static readonly string ServiceName = "iphlpsvc";
internal static readonly string ServiceFriendlyName = "IP Helper";
private static InvalidOperationException InvalidPortProxyType(string type) => new($"Invalid port proxy type ({type}).");
private static readonly string[] ProxyTypes = new[] { "v4tov4", "v4tov6", "v6tov4", "v6tov6" };
private static string GetKeyName(string type)
{
return $@"SYSTEM\CurrentControlSet\Services\PortProxy\{type}\tcp";
}
public static Rule[] GetProxies()
{
var ruleList = new List<Rule>();
foreach (var type in ProxyTypes)
{
var keyName = GetKeyName(type);
var key = Registry.LocalMachine.OpenSubKey(keyName);
if (key is not null)
{
foreach (var name in key.GetValueNames())
{
var listenParts = name.Split('/');
var listenOn = listenParts[0];
if (!int.TryParse(listenParts[1], out var listenPort)) continue;
var connectParts = key.GetValue(name).ToString().Split('/');
var connectTo = connectParts[0];
if (!int.TryParse(connectParts[1], out var connectPort)) continue;
ruleList.Add(new Rule
{
Type = type,
ListenOn = listenOn,
ListenPort = listenPort,
ConnectTo = connectTo,
ConnectPort = connectPort,
});
}
}
}
return ruleList.ToArray();
}
public static void AddOrUpdateProxy(Rule rule)
{
// $"netsh interface portproxy add {rule.Type} listenaddress={rule.ListenOn} listenport={rule.ListenPort} connectaddress={rule.ConnectTo} connectport={rule.ConnectPort}"
if (!ProxyTypes.Contains(rule.Type)) throw InvalidPortProxyType(rule.Type);
var keyName = GetKeyName(rule.Type);
var key = Registry.LocalMachine.OpenSubKey(keyName, true);
var name = $"{rule.ListenOn}/{rule.ListenPort}";
var value = $"{rule.ConnectTo}/{rule.ConnectPort}";
if (key is null) Registry.LocalMachine.CreateSubKey(keyName);
key = Registry.LocalMachine.OpenSubKey(keyName, true);
key?.SetValue(name, value);
}
public static void DeleteProxy(Rule rule)
{
// $"netsh interface portproxy delete {rule.Type} listenaddress={rule.ListenOn} listenport={rule.ListenPort}"
if (!ProxyTypes.Contains(rule.Type)) throw InvalidPortProxyType(rule.Type);
var keyName = GetKeyName(rule.Type);
var key = Registry.LocalMachine.OpenSubKey(keyName, true);
var name = $"{rule.ListenOn}/{rule.ListenPort}";
try
{
key?.DeleteValue(name);
}
catch { }
}
public static bool IsServiceRunning()
{
var hManager = NativeMethods.OpenSCManager(null, null, (uint)GenericRights.GENERIC_READ);
if (hManager == IntPtr.Zero) throw new InvalidOperationException("Open SC Manager failed.");
var hService = NativeMethods.OpenService(hManager, ServiceName, ServiceRights.SERVICE_QUERY_STATUS);
if (hService == IntPtr.Zero)
{
NativeMethods.CloseServiceHandle(hManager);
throw new InvalidOperationException($"Open Service ({ServiceName}) failed.");
}
var status = new ServiceStatus();
NativeMethods.QueryServiceStatus(hService, ref status);
NativeMethods.CloseServiceHandle(hService);
NativeMethods.CloseServiceHandle(hManager);
return status.dwCurrentState == ServiceState.SERVICE_RUNNING;
}
public static void StartService()
{
var hManager = NativeMethods.OpenSCManager(null, null, (uint)GenericRights.GENERIC_READ | (uint)ScmRights.SC_MANAGER_CONNECT);
if (hManager == IntPtr.Zero) throw new InvalidOperationException("Open SC Manager failed.");
var hService = NativeMethods.OpenService(hManager, ServiceName, ServiceRights.SERVICE_START);
if (hService == IntPtr.Zero)
{
NativeMethods.CloseServiceHandle(hManager);
throw new InvalidOperationException($"Open Service ({ServiceName}) failed.");
}
NativeMethods.StartService(hService, 0, null);
NativeMethods.CloseServiceHandle(hService);
NativeMethods.CloseServiceHandle(hManager);
}
public static void ParamChange()
{
var hManager = NativeMethods.OpenSCManager(null, null, (uint)GenericRights.GENERIC_READ);
if (hManager == IntPtr.Zero) throw new InvalidOperationException("Open SC Manager failed.");
var hService = NativeMethods.OpenService(hManager, ServiceName, ServiceRights.SERVICE_PAUSE_CONTINUE);
if (hService == IntPtr.Zero)
{
NativeMethods.CloseServiceHandle(hManager);
throw new InvalidOperationException($"Open Service ({ServiceName}) failed.");
}
var status = new ServiceStatus();
NativeMethods.ControlService(hService, ServiceControls.SERVICE_CONTROL_PARAMCHANGE, ref status);
NativeMethods.CloseServiceHandle(hService);
NativeMethods.CloseServiceHandle(hManager);
}
}
}

148
PortProxyGUI/Utils/Util.cs Normal file
View File

@ -0,0 +1,148 @@
using Microsoft.Win32;
using PortProxyGUI.Data;
using PortProxyGUI.Native;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PortProxyGUI.Utils;
public static class Util
{
internal static readonly string ServiceName = "iphlpsvc";
internal static readonly string ServiceFriendlyName = "IP Helper";
private static InvalidOperationException InvalidPortProxyType(string type) => new($"Invalid port proxy type ({type}).");
private static readonly string[] ProxyTypes = ["v4tov4", "v4tov6", "v6tov4", "v6tov6"];
private static string GetKeyName(string type)
{
return $@"SYSTEM\CurrentControlSet\Services\PortProxy\{type}\tcp";
}
public static Rule[] GetProxies()
{
var ruleList = new List<Rule>();
foreach (var type in ProxyTypes)
{
var keyName = GetKeyName(type);
var key = Registry.LocalMachine.OpenSubKey(keyName);
if (key is not null)
{
foreach (var name in key.GetValueNames())
{
var listenParts = name.Split('/');
var listenOn = listenParts[0];
if (!int.TryParse(listenParts[1], out var listenPort)) continue;
var connectParts = key.GetValue(name).ToString().Split('/');
var connectTo = connectParts[0];
if (!int.TryParse(connectParts[1], out var connectPort)) continue;
ruleList.Add(new Rule
{
Type = type,
ListenOn = listenOn,
ListenPort = listenPort,
ConnectTo = connectTo,
ConnectPort = connectPort,
});
}
}
}
return [.. ruleList];
}
public static void AddOrUpdateProxy(Rule rule)
{
// $"netsh interface portproxy add {rule.Type} listenaddress={rule.ListenOn} listenport={rule.ListenPort} connectaddress={rule.ConnectTo} connectport={rule.ConnectPort}"
if (!ProxyTypes.Contains(rule.Type)) throw InvalidPortProxyType(rule.Type);
var keyName = GetKeyName(rule.Type);
var key = Registry.LocalMachine.OpenSubKey(keyName, true);
var name = $"{rule.ListenOn}/{rule.ListenPort}";
var value = $"{rule.ConnectTo}/{rule.ConnectPort}";
if (key is null) Registry.LocalMachine.CreateSubKey(keyName);
key = Registry.LocalMachine.OpenSubKey(keyName, true);
key?.SetValue(name, value);
}
public static void DeleteProxy(Rule rule)
{
// $"netsh interface portproxy delete {rule.Type} listenaddress={rule.ListenOn} listenport={rule.ListenPort}"
if (!ProxyTypes.Contains(rule.Type)) throw InvalidPortProxyType(rule.Type);
var keyName = GetKeyName(rule.Type);
var key = Registry.LocalMachine.OpenSubKey(keyName, true);
var name = $"{rule.ListenOn}/{rule.ListenPort}";
try
{
key?.DeleteValue(name);
}
catch { }
}
public static bool IsServiceRunning()
{
var hManager = NativeMethods.OpenSCManager(null, null, (uint)GenericRights.GENERIC_READ);
if (hManager == IntPtr.Zero) throw new InvalidOperationException("Open SC Manager failed.");
var hService = NativeMethods.OpenService(hManager, ServiceName, ServiceRights.SERVICE_QUERY_STATUS);
if (hService == IntPtr.Zero)
{
NativeMethods.CloseServiceHandle(hManager);
throw new InvalidOperationException($"Open Service ({ServiceName}) failed.");
}
var status = new ServiceStatus();
NativeMethods.QueryServiceStatus(hService, ref status);
NativeMethods.CloseServiceHandle(hService);
NativeMethods.CloseServiceHandle(hManager);
return status.dwCurrentState == ServiceState.SERVICE_RUNNING;
}
public static void StartService()
{
var hManager = NativeMethods.OpenSCManager(null, null, (uint)GenericRights.GENERIC_READ | (uint)ScmRights.SC_MANAGER_CONNECT);
if (hManager == IntPtr.Zero) throw new InvalidOperationException("Open SC Manager failed.");
var hService = NativeMethods.OpenService(hManager, ServiceName, ServiceRights.SERVICE_START);
if (hService == IntPtr.Zero)
{
NativeMethods.CloseServiceHandle(hManager);
throw new InvalidOperationException($"Open Service ({ServiceName}) failed.");
}
NativeMethods.StartService(hService, 0, null);
NativeMethods.CloseServiceHandle(hService);
NativeMethods.CloseServiceHandle(hManager);
}
public static void ParamChange()
{
var hManager = NativeMethods.OpenSCManager(null, null, (uint)GenericRights.GENERIC_READ);
if (hManager == IntPtr.Zero) throw new InvalidOperationException("Open SC Manager failed.");
var hService = NativeMethods.OpenService(hManager, ServiceName, ServiceRights.SERVICE_PAUSE_CONTINUE);
if (hService == IntPtr.Zero)
{
NativeMethods.CloseServiceHandle(hManager);
throw new InvalidOperationException($"Open Service ({ServiceName}) failed.");
}
var status = new ServiceStatus();
NativeMethods.ControlService(hService, ServiceControls.SERVICE_CONTROL_PARAMCHANGE, ref status);
NativeMethods.CloseServiceHandle(hService);
NativeMethods.CloseServiceHandle(hManager);
}
}