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);
}
}