diff --git a/ServerPickerX/ServerPickerX.csproj b/ServerPickerX/ServerPickerX.csproj index 62d2272..64d084c 100644 --- a/ServerPickerX/ServerPickerX.csproj +++ b/ServerPickerX/ServerPickerX.csproj @@ -6,6 +6,8 @@ true true + + true partial @@ -20,8 +22,8 @@ https://github.com/FN-FAL113/server-picker-x https://github.com/FN-FAL113/server-picker-x Assets\favicon.ico - 1.0.3.0 - 1.0.3.0 + 1.0.4.0 + 1.0.4.0 @@ -31,6 +33,10 @@ + + libs\Interop.NetFwTypeLib.dll + true + diff --git a/ServerPickerX/Services/SystemFirewalls/WindowsFirewallService.cs b/ServerPickerX/Services/SystemFirewalls/WindowsFirewallService.cs index 433da09..4684002 100644 --- a/ServerPickerX/Services/SystemFirewalls/WindowsFirewallService.cs +++ b/ServerPickerX/Services/SystemFirewalls/WindowsFirewallService.cs @@ -10,6 +10,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using NetFwTypeLib; namespace ServerPickerX.Services.SystemFirewalls { @@ -20,73 +21,64 @@ public class WindowsFirewallService( IProcessService _processService ) : ISystemFirewallService { + private const string _firewallRulePrefix = "server_picker_x_"; + private const NET_FW_RULE_DIRECTION_ _firewallRuleDirectionOutbound = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_OUT; + private const NET_FW_ACTION_ _firewallRuleActionBlock = NET_FW_ACTION_.NET_FW_ACTION_BLOCK; + private const int _firewallRuleProtocolAny = 256; + private const int _firewallRuleProfilesAll = int.MaxValue; + public async Task BlockServersAsync(ObservableCollection serverModels) { - foreach (var serverModel in serverModels) + try { - string ipAddresses = string.Join(",", serverModel.RelayModels.Select(s => s.IPv4).ToList()); - - using var process = _processService.CreateProcess("cmd.exe"); - - process.StartInfo.Arguments = $"/c {Path.Combine(Environment.SystemDirectory, "netsh.exe")} " + - "advfirewall firewall " + - "add rule " + - "name=server_picker_x_" + serverModel.Description.Replace(" ", "") + - " dir=out action=block protocol=ANY " + "remoteip=" + ipAddresses; - - try - { - process.Start(); - await process.WaitForExitAsync(); - - string stdOut = process.StandardOutput.ReadToEnd().Trim(); - string stdErr = process.StandardError.ReadToEnd().Trim(); + INetFwPolicy2 firewallPolicy = GetFirewallPolicyApi(); + INetFwRules firewallRules = firewallPolicy.Rules; - if (process.ExitCode > 0) - { - await _loggerService.LogWarningAsync("StdOut: " + stdOut + " StdErr: " + stdErr); - } - } - catch (Exception ex) + foreach (var serverModel in serverModels) { - // Perform debugging here if necessary (log error or through debugger breakpoints) - throw; + string ruleName = GetFirewallRuleName(serverModel); + string ipAddresses = string.Join(",", serverModel.RelayModels.Select(s => s.IPv4)); + + RemoveFirewallRuleByName(firewallRules, ruleName); + + INetFwRule firewallRule = CreateFirewallRuleApi(); + firewallRule.Name = ruleName; + firewallRule.Description = serverModel.Description; + firewallRule.Direction = _firewallRuleDirectionOutbound; + firewallRule.Action = _firewallRuleActionBlock; + firewallRule.Protocol = _firewallRuleProtocolAny; + firewallRule.RemoteAddresses = ipAddresses; + firewallRule.Enabled = true; + firewallRule.Profiles = _firewallRuleProfilesAll; + + firewallRules.Add(firewallRule); } } + catch (Exception ex) + { + await _loggerService.LogErrorAsync(ex.Message); + throw; + } } public async Task UnblockServersAsync(ObservableCollection serverModels) { - foreach (var serverModel in serverModels) + try { - string ipAddresses = string.Join(",", serverModel.RelayModels.Select(s => s.IPv4).ToList()); - - using var process = _processService.CreateProcess("cmd.exe"); - - process.StartInfo.Arguments = $"/c {Path.Combine(Environment.SystemDirectory, "netsh.exe")} " + - "advfirewall firewall " + - "delete rule " + - "name=server_picker_x_" + serverModel.Description.Replace(" ", ""); + INetFwPolicy2 firewallPolicy = GetFirewallPolicyApi(); + INetFwRules firewallRules = firewallPolicy.Rules; - try - { - process.Start(); - await process.WaitForExitAsync(); - - string stdOut = process.StandardOutput.ReadToEnd().Trim(); - string stdErr = process.StandardError.ReadToEnd().Trim(); - - if (process.ExitCode > 0) - { - await _loggerService.LogWarningAsync("StdOut: " + stdOut + " StdErr: " + stdErr); - } - } - catch (Exception ex) + foreach (var serverModel in serverModels) { - // Perform debugging here if necessary (log error or through debugger breakpoints) - throw; + string ruleName = GetFirewallRuleName(serverModel); + RemoveFirewallRuleByName(firewallRules, ruleName); } } + catch (Exception ex) + { + await _loggerService.LogErrorAsync(ex.Message); + throw; + } } public async Task ResetFirewallAsync() @@ -97,10 +89,7 @@ public async Task ResetFirewallAsync() MsBox.Avalonia.Enums.Icon.Warning ); - if (!result) - { - return; - } + if (!result) return; using Process process = _processService.CreateProcess("cmd.exe"); @@ -127,9 +116,36 @@ await _messageBoxService.ShowMessageBoxAsync( } catch (Exception ex) { - // Perform debugging here if necessary (log error or through debugger breakpoints) + await _loggerService.LogErrorAsync(ex.Message); throw; } } + + public INetFwPolicy2 GetFirewallPolicyApi() + => (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("E2B3C97F-6AE1-41AC-817A-F6F92166D7DD"))!)!; + + public INetFwRule CreateFirewallRuleApi() + => (INetFwRule)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("2C5BC43E-3369-4C33-AB0C-BE9469677AF4"))!)!; + + public string GetFirewallRuleName(ServerModel serverModel) + => _firewallRulePrefix + serverModel.Description.Replace(" ", ""); + + public void RemoveFirewallRuleByName(INetFwRules firewallRules, string ruleName) + { + while (TryGetFirewallRule(firewallRules, ruleName) != null) + { + firewallRules.Remove(ruleName); + } + } + + public INetFwRule? TryGetFirewallRule(INetFwRules firewallRules, string ruleName) + { + try + { + return firewallRules.Item(ruleName); + } catch { + return null; + } + } } -} \ No newline at end of file +} diff --git a/ServerPickerX/libs/Interop.NetFwTypeLib.dll b/ServerPickerX/libs/Interop.NetFwTypeLib.dll new file mode 100644 index 0000000..d52e0ed Binary files /dev/null and b/ServerPickerX/libs/Interop.NetFwTypeLib.dll differ