C#增删查防火墙例外

C#增删查防火墙例外

当我们的程序涉及到网络通讯时,通常需要添加防火墙例外,否则程序会被防火墙拦截,导致通讯失败。在 .NET/C# 中,可以通过如下三种方式来对 防火墙例外 进行增、删、查:

  • 执行 netsh advfirewall firewall 命令
  • 使用 NetFwTypeLib COM 组件
  • 调用 PowerShell 脚本

其中,前两种方案较为常用,本文将详细展示其实现方法。对 PowerShell 方案感兴趣的,可访问 Windows PowerShell - NetSecurity 来了解相关脚本。

执行 netsh advfirewall firewall 命令

Windows 提供了防火墙相关的命令,后台调起 命令行工具(cmd.exe) ,通过运行 netsh advfirewall firewall 的相关命令来实现对防火墙规则的操作。

private static string FirewallCmd { get; } = "netsh advfirewall firewall";

/// <summary>
/// Adds firewall exception for the specified program file.
/// </summary>
/// <param name="fileName">The full path of the specified program file.</param>
public static void AddException(string fileName)
{
    AddRule(fileName, Path.GetFileName(fileName));
    AddRule(fileName, Path.GetFileNameWithoutExtension(fileName));
}

/// <summary>
/// Removes the firewall exception of the specified program file.
/// </summary>
/// <param name="fileName">The full path of the specified program file.</param>
public static void RemoveException(string fileName)
{
    RemoveRule(fileName, Path.GetFileName(fileName));
    RemoveRule(fileName, Path.GetFileNameWithoutExtension(fileName));
}

/// <summary>
/// Determines whether the firewall exception of the specified program file exists.
/// </summary>
/// <param name="fileName">The full path of the specified program file.</param>
/// <returns></returns>
public static bool ExceptionExists(string fileName)
{
    var nameWithEx = Path.GetFileName(fileName);

    var cmd = $"{FirewallCmd} show rule name ={nameWithEx} verbose";
    var output = CmdRunner.ExecuteWithOutput(cmd);

    if (!string.IsNullOrEmpty(output))
    {
        if (output.Contains(fileName))
        {
            return true;
        }
    }

    return false;
}

private static void AddRule(string appName, string ruleName)
{
    var commandIn = $"{FirewallCmd} add rule name=\"{ruleName}\" dir=in action=allow program=\"{appName}\"";
    var commandOut = $"{FirewallCmd} add rule name=\"{ruleName}\" dir=out action=allow program=\"{appName}\"";

    CmdRunner.Execute(commandIn);
    CmdRunner.Execute(commandOut);
}

private static void RemoveRule(string appName, string ruleName)
{
    var commandIn = $"{FirewallCmd} delete rule name=\"{ruleName}\" dir=in program=\"{appName}\"";
    var commandOut = $"{FirewallCmd} delete rule name=\"{ruleName}\" dir=out program=\"{appName}\"";

    CmdRunner.Execute(commandIn);
    CmdRunner.Execute(commandOut);
}

使用 NetFwTypeLib COM 组件

NetFwTypeLib 是系统提供的 COM 组件,该组件定义了防火墙的相关接口。首先,在项目中添加对 NetFwTypeLib 的引用,然后通过 INetFwPolicy2 实例和 INetFwRule 实例来实现对防火墙规则的操作。

private const string FwMgr = "HNetCfg.FwMgr";
private const string FwApp = "HNetCfg.FwAuthorizedApplication";
private const string FwPolicy = "HNetCfg.FwPolicy2";
private const string FwRule = "HNetCfg.FWRule";

/// <summary>
/// Adds firewall exception for the specified program file through `NetFwTypeLib` COM.
/// </summary>
/// <param name="fileName">The full path of the specified program file.</param>
public static void AddExceptionByCom(string fileName)
{
    AddRuleByCom(fileName, Path.GetFileName(fileName));
    AddRuleByCom(fileName, Path.GetFileNameWithoutExtension(fileName));
}

/// <summary>
/// Removes the firewall exception of the specified program file through `NetFwTypeLib` COM.
/// </summary>
/// <param name="fileName">The full path of the specified program file.</param>
public static void RemoveExceptionByCom(string fileName)
{
    RemoveRuleByCom(fileName, Path.GetFileName(fileName));
    RemoveRuleByCom(fileName, Path.GetFileNameWithoutExtension(fileName));
}

private static void AddRuleByCom(string appName, string ruleName)
{
    var policy = (INetFwPolicy2) Activator.CreateInstance(Type.GetTypeFromProgID(FwPolicy));

    // Inbound Rule
    var ruleIn = (INetFwRule) Activator.CreateInstance(Type.GetTypeFromProgID(FwRule));

    ruleIn.Name = ruleName;
    ruleIn.ApplicationName = appName;
    ruleIn.Enabled = true;

    policy.Rules.Add(ruleIn);

    // Outbound Rule
    var ruleOut = (INetFwRule) Activator.CreateInstance(Type.GetTypeFromProgID(FwRule));

    ruleOut.Name = ruleName;
    ruleOut.ApplicationName = appName;
    ruleOut.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_OUT;
    ruleOut.Enabled = true;

    policy.Rules.Add(ruleOut);
}

private static void RemoveRuleByCom(string appName, string ruleName)
{
    var policy = (INetFwPolicy2) Activator.CreateInstance(Type.GetTypeFromProgID(FwPolicy));
    var rules = policy.Rules.OfType<INetFwRule>();

    foreach (var rule in rules.Where(x => x.Name == ruleName && x.ApplicationName == appName))
    {
        policy.Rules.Remove(rule.Name);
    }
}

猜你喜欢

转载自blog.csdn.net/Iron_Ye/article/details/82732078