C# 防火墙,删除特定条目

C# Firewall, delete specific entry

我目前正在为一家公司编写 windows-firewallmanager。
问题是,我只能按名称而不是 INetFwRule 对象或其他东西删除条目。
有些条目具有两次相同的名称,其中一个用于 TCP,另一个用于 UDP,我们可能只想删除其中一个。
我可以删除两者,然后再创建其中之一,但我不想使用该解决方法。
有人对此有简单的解决方案吗?

您只能使用 INetFwRules 界面按名称删除规则,这似乎设计得很糟糕 API 因为不同的规则可以有相同的名称。解决方法是不仅按名称过滤规则,还按指定要删除的规则的其他属性过滤规则。找到要删除的规则后,您可以使用 INetFwRule 界面将规则重命名为唯一名称。

然后您可以使用这个唯一的临时名称删除规则。

    public static void RemoveFirewallRules(string RuleName = "BreakermindCom")
{
    try
    {
        Type tNetFwPolicy2 = Type.GetTypeFromProgID("HNetCfg.FwPolicy2");
        INetFwPolicy2 fwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(tNetFwPolicy2);
        var currentProfiles = fwPolicy2.CurrentProfileTypes;               

        // Lista rules
        // List<INetFwRule> RuleList = new List<INetFwRule>();

        foreach (INetFwRule rule in fwPolicy2.Rules)
        {
            // Add rule to list
            // RuleList.Add(rule);
            // Console.WriteLine(rule.Name);
            if (rule.Name.IndexOf(RuleName) != -1)
            {
                // Now add the rule
                INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));                     
                firewallPolicy.Rules.Remove(rule.Name);
                Console.WriteLine(rule.Name + " has been deleted from Firewall Policy");
            }
        }
    }
    catch (Exception r)
    {
        Console.WriteLine("Error delete rule from firewall");
    }}

看看这个

根据@“Martin Liversage”的建议,这是一个使用 C# 互操作测试的有效 C++ 示例。

“AddAppFirewallRule”只会添加不存在的防火墙规则。
“RemoveAppFirewallRule”将删除与 exe 路径匹配的所有防火墙规则。

C/C++

#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include <netfw.h>
#include <atlcomcli.h>

#include "Exports.h"

HRESULT WFCOMInitialize(INetFwPolicy2** ppNetFwPolicy2)
{
    return CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), (void**)ppNetFwPolicy2);
}

extern "C"
{
    MyFrameworkOSNative_EXPORT int MyFrameworkOSNative_AddAppFirewallRule(int privateNetworks, int publicNetworks, int domainNetworks, wchar_t* exePath, wchar_t* name, wchar_t* groupName, wchar_t* desc, wchar_t* ports, int tcp, int udp)
    {
        // declare locals
        int result = 0;
        HRESULT addRuleResult;

        BSTR ruleName = SysAllocString(name);
        BSTR ruleGroup = SysAllocString(groupName);
        BSTR ruleDesc = SysAllocString(desc);
        BSTR ruleExe = SysAllocString(exePath);
        BSTR rulePorts = nullptr;
        if (ports != nullptr) rulePorts = SysAllocString(ports);

        INetFwPolicy2* policy = nullptr;
        INetFwRules* rules = nullptr;
        INetFwRule* rule = nullptr;
        long profilesBitMask = 0;

        HRESULT iterateResult = 0;
        IUnknown* rulesCollection = nullptr;
        IEnumVARIANT* variant = nullptr;
        CComVariant var = {};
        ULONG fetched = 0;
        bool found = false;

        // init
        if (FAILED(WFCOMInitialize(&policy))) goto Cleanup;
        if (FAILED(policy->get_Rules(&rules))) goto Cleanup;

        //if (FAILED(policy->get_CurrentProfileTypes(&profilesBitMask))) goto Cleanup;
        if (privateNetworks) profilesBitMask |= NET_FW_PROFILE2_PRIVATE;
        if (publicNetworks) profilesBitMask |= NET_FW_PROFILE2_PUBLIC;
        if (domainNetworks) profilesBitMask |= NET_FW_PROFILE2_DOMAIN;

        if (FAILED(CoCreateInstance(__uuidof(NetFwRule), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwRule), (void**)&rule))) goto Cleanup;

        // setup rule
        rule->put_Name(ruleName);
        rule->put_Description(ruleDesc);
        rule->put_ApplicationName(ruleExe);
        if (tcp && udp) rule->put_Protocol(NET_FW_IP_PROTOCOL_ANY);
        else if (tcp) rule->put_Protocol(NET_FW_IP_PROTOCOL_TCP);
        else if (udp) rule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
        if (rulePorts != nullptr) rule->put_LocalPorts(rulePorts);
        rule->put_Direction(NET_FW_RULE_DIR_MAX);
        rule->put_Grouping(ruleGroup);
        rule->put_Profiles(profilesBitMask);
        rule->put_Action(NET_FW_ACTION_ALLOW);
        rule->put_Enabled(VARIANT_TRUE);

        // get rules enumerator
        if (FAILED(rules->get__NewEnum(&rulesCollection))) goto Cleanup;
        if (FAILED(rulesCollection->QueryInterface(__uuidof(IEnumVARIANT), (void**)&variant))) goto Cleanup;

        // enumerate rules to check if it already exists
        var.Clear();
        iterateResult = variant->Next(1, &var, &fetched);
        while (SUCCEEDED(iterateResult) && iterateResult != S_FALSE)
        {
            BSTR ruleEXEPath = nullptr;
            INetFwRule* existingRule = nullptr;
            long exitingRuleProfileBitMask = 0;
            if (FAILED((V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&existingRule)))) goto Cleanup;
            if (FAILED(existingRule->get_ApplicationName(&ruleEXEPath))) goto Cleanup;
            if (FAILED(existingRule->get_Profiles(&exitingRuleProfileBitMask))) goto Cleanup;
            if (ruleEXEPath != nullptr && wcscmp(ruleEXEPath, exePath) == 0 && exitingRuleProfileBitMask == profilesBitMask)// check if exe paths match
            {
                BSTR existingRuleName = nullptr;
                if (SUCCEEDED(existingRule->get_Name(&existingRuleName)))
                {
                    if (existingRuleName != nullptr)
                    {
                        if (wcscmp(ruleName, existingRuleName) == 0) found = true;
                        SysFreeString(existingRuleName);
                    }
                }
            }

            // cleanup iteration
            if (existingRule != nullptr)
            {
                existingRule->Release();
                existingRule = nullptr;
            }
            if (ruleEXEPath != nullptr) SysFreeString(ruleEXEPath);

            // exit loop if found
            if (found) break;

            // get next item in collection
            var.Clear();
            iterateResult = variant->Next(1, &var, &fetched);
        }

        // add rule if it doesn't already exist
        if (!found)
        {
            addRuleResult = rules->Add(rule);
            if (FAILED(addRuleResult)) goto Cleanup;
        }

        result = 1;// success

        // cleanup resources
    Cleanup:;
        if (variant != nullptr) variant->Release();
        if (rulesCollection != nullptr) rulesCollection->Release();

        if (ruleName != nullptr) SysFreeString(ruleName);
        if (ruleGroup != nullptr) SysFreeString(ruleGroup);
        if (ruleDesc != nullptr) SysFreeString(ruleDesc);
        if (ruleExe != nullptr) SysFreeString(ruleExe);
        if (rulePorts != nullptr) SysFreeString(rulePorts);

        if (rule != nullptr) rule->Release();
        if (rules != nullptr) rules->Release();
        if (policy != nullptr) policy->Release();

        return result;
    }

    MyFrameworkOSNative_EXPORT int MyFrameworkOSNative_RemoveAppFirewallRule(wchar_t* exePath)
    {
        // declare locals
        int result = 0;

        INetFwPolicy2* policy = nullptr;
        INetFwRules* rules = nullptr;
        INetFwRule* rule = nullptr;
        long profilesBitMask = 0;

        HRESULT iterateResult = 0;
        IUnknown* rulesCollection = nullptr;
        IEnumVARIANT* variant = nullptr;
        CComVariant var = {};
        ULONG fetched = 0;
        bool found = false;

        // init
        if (FAILED(WFCOMInitialize(&policy))) goto Cleanup;
        if (FAILED(policy->get_Rules(&rules))) goto Cleanup;

        // get rules enumerator
        if (FAILED(rules->get__NewEnum(&rulesCollection))) goto Cleanup;
        if (FAILED(rulesCollection->QueryInterface(__uuidof(IEnumVARIANT), (void**)&variant))) goto Cleanup;

        // enumerate rules
        var.Clear();
        iterateResult = variant->Next(1, &var, &fetched);
        while (SUCCEEDED(iterateResult) && iterateResult != S_FALSE)
        {
            BSTR ruleEXEPath = nullptr;
            if (FAILED((V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&rule)))) goto Cleanup;
            if (FAILED(rule->get_ApplicationName(&ruleEXEPath))) goto Cleanup;
            if (ruleEXEPath != nullptr && wcscmp(ruleEXEPath, exePath) == 0)// check if exe paths match
            {
                found = true;
                SysFreeString(ruleEXEPath);
                BSTR ruleName = nullptr;
                if (FAILED(rule->get_Name(&ruleName)))
                {
                    if (ruleName != nullptr) SysFreeString(ruleName);
                    goto Cleanup;
                }
                if (FAILED(rules->Remove(ruleName)))
                {
                    if (ruleName != nullptr) SysFreeString(ruleName);
                    goto Cleanup;
                }
                if (ruleName != nullptr) SysFreeString(ruleName);

                // get next item in collection
                var.Clear();
                iterateResult = variant->Next(1, &var, &fetched);
                continue;// continue to scan for more rules with same criteria
            }

            // cleanup iteration
            if (rule != nullptr)
            {
                rule->Release();
                rule = nullptr;
            }
            if (ruleEXEPath != nullptr) SysFreeString(ruleEXEPath);

            // get next item in collection
            var.Clear();
            iterateResult = variant->Next(1, &var, &fetched);
        }
        
        if (!found) goto Cleanup;
        result = 1;// success

        // cleanup resources
    Cleanup:;
        if (variant != nullptr) variant->Release();
        if (rulesCollection != nullptr) rulesCollection->Release();

        if (rule != nullptr) rule->Release();
        if (rules != nullptr) rules->Release();
        if (policy != nullptr) policy->Release();

        return result;
    }
}

C#

[DllImport("MyFramework.OS.Native.dll")]
private static unsafe extern int VMyFrameworkOSNative_AddAppFirewallRule(int privateNetworks, int publicNetworks, int domainNetworks, char* exePath, char* name, char* groupName, char* desc, char* ports, int tcp, int udp);

[DllImport("MyFramework.OS.Native.dll")]
private static unsafe extern int MyFrameworkOSNative_RemoveAppFirewallRule(char* exePath);

public static unsafe bool AddAppFirewallRule(bool privateNetworks, bool publicNetworks, bool domainNetworks, string exePath, string ruleName, string ruleDesc, int port = -1, bool tcp = true, bool udp = true)
{
    // ensure COM is init
    Ole32.CoInitialize(IntPtr.Zero);

    // invoke native method
    string portValue = port.ToString();
    fixed (char* exePathPtr = exePath)
    fixed (char* ruleNamePtr = ruleName)
    fixed (char* ruleDescPtr = ruleDesc)
    fixed (char* portValuePtr = portValue)
    {
        return MyFrameworkOSNative_AddAppFirewallRule
        (
            privateNetworks ? 1 : 0,
            publicNetworks ? 1 : 0,
            domainNetworks ? 1 : 0,
            exePathPtr,
            ruleNamePtr, ruleNamePtr,
            ruleDescPtr,
            port > 0 ? portValuePtr : null,
            tcp ? 1 : 0, udp ? 1 : 0
        ) != 0;
    }
}

public static unsafe bool RemoveAppFirewallRule(string exePath)
{
    // ensure COM is init
    Ole32.CoInitialize(IntPtr.Zero);

    // invoke native method
    fixed (char* exePathPtr = exePath)
    {
        return VMyFrameworkOSNative_RemoveAppFirewallRule(exePathPtr) != 0;
    }
}

单元测试

[Fact]
public void AddAppFirewallRule()
{
    using (var lib = new LibHandle("MyFramework.OS.Native.dll"))
    {
        Assert.True(NetworkUtils.AddAppFirewallRule(true, true, false, @"<Path-To-Exe>", "TestRule", "Test Rule Desc"));
    }
}

[Fact]
public void RemoveAppFirewallRule()
{
    using (var lib = new LibHandle("MyFramework.OS.Native.dll"))
    {
        Assert.True(NetworkUtils.RemoveAppFirewallRule(@"<Path-To-Exe>"));
    }
}