Skip to content
Open
129 changes: 122 additions & 7 deletions NtCoreLib/Net/Firewall/FirewallConditionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
using System.Net;
using System.Net.Sockets;
using NtCoreLib.Security.Authorization;
using NtCoreLib.Win32.Rpc.EndpointMapper;
using NtCoreLib.Win32.Rpc.Transport;

namespace NtCoreLib.Net.Firewall;

Expand Down Expand Up @@ -130,27 +132,58 @@ public void AddConditionFlags(FirewallMatchType match_type, FirewallConditionFla
}

/// <summary>
/// Add IP address.
/// Add IP address for non-RPC layers.
/// </summary>
/// <param name="match_type">The match type for the condition.</param>
/// <param name="remote">True to specify remote, false for local.</param>
/// <param name="address">The low IP address.</param>
public void AddIpAddress(FirewallMatchType match_type, bool remote, IPAddress address)
{
AddCondition(match_type, remote ? FirewallConditionGuids.FWPM_CONDITION_IP_REMOTE_ADDRESS : FirewallConditionGuids.FWPM_CONDITION_IP_LOCAL_ADDRESS,
AddIpAddress(match_type, remote, address, false);
}

/// <summary>
/// Add IP address, optionally using address family-specific
/// fields, which appear in the RPC_EPMAP and RPC_UM layers.
/// </summary>
/// <param name="match_type">The match type for the condition.</param>
/// <param name="remote">True to specify remote, false for local.</param>
/// <param name="address">The low IP address.</param>
/// <param name="is_rpc_layer">True if the condition is for use in an RPC firewall layer.</param>
public void AddIpAddress(FirewallMatchType match_type, bool remote, IPAddress address, bool is_rpc_layer)
{
AddCondition(
match_type,
FirewallConditionGuids.FromIPAddress(address, remote, is_rpc_layer),
FirewallValue.FromIpAddress(address));
}

/// <summary>
/// Add IP address range.
/// Add IP address range for non-RPC layers.
/// </summary>
/// <param name="remote">True to specify remote, false for local.</param>
/// <param name="low_address">The low IP address.</param>
/// <param name="high_address">The high IP address.</param>
public void AddIpRange(bool remote, IPAddress low_address, IPAddress high_address)
{
AddConditionRange(remote ? FirewallConditionGuids.FWPM_CONDITION_IP_REMOTE_ADDRESS : FirewallConditionGuids.FWPM_CONDITION_IP_LOCAL_ADDRESS,
FirewallValue.FromIpAddress(low_address), FirewallValue.FromIpAddress(high_address));
AddIpRange(remote, low_address, high_address, false);
}


/// <summary>
/// Add IP address range, optionally using address family-specific
/// fields, which appear in the RPC_EPMAP and RPC_UM layers.
/// </summary>
/// <param name="remote">True to specify remote, false for local.</param>
/// <param name="low_address">The low IP address.</param>
/// <param name="high_address">The high IP address.</param>
/// <param name="is_rpc_layer">True if the condition is for use in an RPC firewall layer.</param>
public void AddIpRange(bool remote, IPAddress low_address, IPAddress high_address, bool is_rpc_layer)
{
AddConditionRange(
FirewallConditionGuids.FromIPAddress(low_address, remote, is_rpc_layer),
FirewallValue.FromIpAddress(low_address),
FirewallValue.FromIpAddress(high_address));
}

/// <summary>
Expand Down Expand Up @@ -280,7 +313,17 @@ public void AddProcess(FirewallMatchType match_type, int process_id)
}

/// <summary>
/// Add the RPC UUID.
/// Add a condition matching an RPC protocol sequence.
/// </summary>
/// <param name="match_type">Match type.</param>
/// <param name="protocol">The RPC protocol sequence.</param>
public void AddRpcProtocol(FirewallMatchType match_type, RpcProtocolSequenceIdentifier protocol)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_RPC_PROTOCOL, FirewallValue.FromUInt8((byte)protocol));
}

/// <summary>
/// Add a condition matching an RPC interface UUID.
/// </summary>
/// <param name="match_type">Match type.</param>
/// <param name="uuid">The RPC UUID.</param>
Expand All @@ -289,6 +332,79 @@ public void AddRpcUuid(FirewallMatchType match_type, Guid uuid)
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_RPC_IF_UUID, FirewallValue.FromGuid(uuid));
}

/// <summary>
/// Add a condition matching an RPC interface version.
/// </summary>
/// <param name="match_type">Match type.</param>
/// <param name="version">The RPC interface version.</param>
public void AddRpcInterfaceVersion(FirewallMatchType match_type, int version)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_RPC_IF_VERSION, FirewallValue.FromUInt16((ushort)version));
}

/// <summary>
/// Add a condition matching the RPC remote user token.
/// </summary>
/// <param name="match_type">The match type for the condition.</param>
/// <param name="security_descriptor">The security descriptor.</param>
public void AddRpcRemoteUser(FirewallMatchType match_type, SecurityDescriptor security_descriptor)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_REMOTE_USER_TOKEN,
FirewallValue.FromSecurityDescriptor(security_descriptor));
}

/// <summary>
/// Add a condition matching the RPC remote user token.
/// </summary>
/// <param name="match_type">The match type.</param>
/// <param name="token">The token.</param>
public void AddRpcRemoteUserToken(FirewallMatchType match_type, NtToken token)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_REMOTE_USER_TOKEN,
FirewallValue.FromTokenInformation(token));
}

/// <summary>
/// Add a condition matching the RPC authentication level.
/// </summary>
/// <param name="match_type">Match type.</param>
/// <param name="auth_level">The RPC authentication level.</param>
public void AddRpcAuthenticationLevel(FirewallMatchType match_type, RpcAuthenticationLevel auth_level)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_RPC_AUTH_LEVEL, FirewallValue.FromUInt8((byte)auth_level));
}

/// <summary>
/// Add a condition matching the RPC authentication type.
/// </summary>
/// <param name="match_type">Match type.</param>
/// <param name="auth_type">The RPC authentication type.</param>
public void AddRpcAuthenticationType(FirewallMatchType match_type, RpcAuthenticationType auth_type)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_RPC_AUTH_TYPE, FirewallValue.FromUInt8((byte)auth_type));
}

/// <summary>
/// Add a condition matching the RPC opnum.
/// </summary>
/// <remarks>Available in Windows 11, Server 2025 or later.</remarks>
/// <param name="match_type">Match type.</param>
/// <param name="op_num">The RPC Authentication Type.</param>
public void AddRpcOpNum(FirewallMatchType match_type, int op_num)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_RPC_OPNUM, FirewallValue.FromUInt16((ushort)op_num));
}

/// <summary>
/// Add a condition matching a DCOM AppId.
/// </summary>
/// <param name="match_type">Match type.</param>
/// <param name="uuid">The DCOM AppId.</param>
public void AddDcomAppId(FirewallMatchType match_type, Guid uuid)
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_DCOM_APP_ID, FirewallValue.FromGuid(uuid));
}

/// <summary>
/// Add a network event type.
/// </summary>
Expand All @@ -298,7 +414,6 @@ public void AddNetEventType(FirewallMatchType match_type, FirewallNetEventType t
{
AddCondition(match_type, FirewallConditionGuids.FWPM_CONDITION_NET_EVENT_TYPE, FirewallValue.FromUInt32((uint)type));
}

#endregion

#region Constructors
Expand Down
30 changes: 29 additions & 1 deletion NtCoreLib/Net/Firewall/FirewallConditionGuids.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
// limitations under the License.

using System;
using System.Net;
using System.Net.Sockets;

namespace NtCoreLib.Net.Firewall;

Expand Down Expand Up @@ -222,6 +224,8 @@ public static class FirewallConditionGuids
public static Guid FWPM_CONDITION_RPC_AUTH_TYPE = new(0xdaba74ab, 0x0d67, 0x43e7, 0x98, 0x6e, 0x75, 0xb8, 0x4f, 0x82, 0xf5, 0x94);
// e5a0aed5-59ac-46ea-be05-a5f05ecf446e
public static Guid FWPM_CONDITION_RPC_AUTH_LEVEL = new(0xe5a0aed5, 0x59ac, 0x46ea, 0xbe, 0x05, 0xa5, 0xf0, 0x5e, 0xcf, 0x44, 0x6e);
// d58efb76-aab7-4148-a87e-9581134129b9
public static Guid FWPM_CONDITION_RPC_OPNUM = new(0xd58efb76, 0xaab7, 0x4148, 0xa8, 0x7e, 0x95, 0x81, 0x13, 0x41, 0x29, 0xb9);
// 0d306ef0-e974-4f74-b5c7-591b0da7d562
public static Guid FWPM_CONDITION_SEC_ENCRYPT_ALGORITHM = new(0x0d306ef0, 0xe974, 0x4f74, 0xb5, 0xc7, 0x59, 0x1b, 0x0d, 0xa7, 0xd5, 0x62);
// 4772183b-ccf8-4aeb-bce1-c6c6161c8fe4
Expand Down Expand Up @@ -364,7 +368,7 @@ public static bool IsNetworkLayer(Guid condition_key)
public static bool IsTunnelType(Guid condition_key)
{
return condition_key == FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE ||
condition_key == FWPM_LOCAL_CONDITION_TUNNEL_TYPE ||
condition_key == FWPM_LOCAL_CONDITION_TUNNEL_TYPE ||
condition_key == FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE;
}

Expand All @@ -382,5 +386,29 @@ public static bool IsUserId(Guid condition_key)
condition_key == FWPM_CONDITION_ALE_REMOTE_MACHINE_ID;
}

internal static Guid FromIPAddress(IPAddress address, bool remote, bool rpc_layer)
{
// RPC_UM and RPC_EPMAP layers use _V4/_V6 suffixes
if (rpc_layer)
{
if (address.AddressFamily == AddressFamily.InterNetwork)
{
return remote ?
FWPM_CONDITION_IP_REMOTE_ADDRESS_V4 :
FWPM_CONDITION_IP_LOCAL_ADDRESS_V4;
}
else if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
return remote ?
FWPM_CONDITION_IP_REMOTE_ADDRESS_V6 :
FWPM_CONDITION_IP_LOCAL_ADDRESS_V6;
}

throw new ArgumentException("Must specify V4 or V6 IP address.", nameof(address));
}

return remote ? FWPM_CONDITION_IP_REMOTE_ADDRESS : FWPM_CONDITION_IP_LOCAL_ADDRESS;
}

#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
}
70 changes: 70 additions & 0 deletions NtCoreLib/Net/Firewall/FirewallEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,41 @@ public IEnumerable<FirewallLayer> EnumerateLayers()
return EnumerateLayers(true).Result;
}

/// <summary>
/// Add a sub-layer.
/// </summary>
/// <param name="builder">The builder used to create the sub-layer.</param>
/// <param name="security_descriptor">Optional security descriptor.</param>
/// <param name="throw_on_error">True to throw on error.</param>
/// <returns>The NT status.</returns>
public NtStatus AddSubLayer(FirewallSubLayerBuilder builder, SecurityDescriptor security_descriptor, bool throw_on_error)
{
using var list = new DisposableList();
var sd_buffer = security_descriptor != null ? list.AddResource(security_descriptor.ToSafeBuffer()) : SafeHGlobalBuffer.Null;
return FirewallNativeMethods.FwpmSubLayerAdd0(_handle, builder.ToStruct(list),
sd_buffer).ToNtException(throw_on_error);
}

/// <summary>
/// Delete a sub-layer.
/// </summary>
/// <param name="key">The sub-layer key.</param>
/// <param name="throw_on_error">True to throw on error.</param>
/// <returns>The NT status.</returns>
public NtStatus DeleteSubLayer(Guid key, bool throw_on_error)
{
return FirewallNativeMethods.FwpmProviderDeleteByKey0(_handle, key).ToNtException(throw_on_error);
}

/// <summary>
/// Delete a sub-layer.
/// </summary>
/// <param name="key">The sub-layer key.</param>
public void DeleteSubLayer(Guid key)
{
DeleteSubLayer(key, true);
}

/// <summary>
/// Get a sub-layer by its key.
/// </summary>
Expand Down Expand Up @@ -828,6 +863,41 @@ public void DeleteFilter(ulong id)
DeleteFilter(id, true);
}

/// <summary>
/// Add a provider.
/// </summary>
/// <param name="builder">The builder used to create the provider.</param>
/// <param name="security_descriptor">Optional security descriptor.</param>
/// <param name="throw_on_error">True to throw on error.</param>
/// <returns>The NT status.</returns>
public NtStatus AddProvider(FirewallProviderBuilder builder, SecurityDescriptor security_descriptor, bool throw_on_error)
{
using var list = new DisposableList();
var sd_buffer = security_descriptor != null ? list.AddResource(security_descriptor.ToSafeBuffer()) : SafeHGlobalBuffer.Null;
return FirewallNativeMethods.FwpmProviderAdd0(_handle, builder.ToStruct(list),
sd_buffer).ToNtException(throw_on_error);
}

/// <summary>
/// Delete a provider.
/// </summary>
/// <param name="key">The provider key.</param>
/// <param name="throw_on_error">True to throw on error.</param>
/// <returns>The NT status.</returns>
public NtStatus DeleteProvider(Guid key, bool throw_on_error)
{
return FirewallNativeMethods.FwpmProviderDeleteByKey0(_handle, key).ToNtException(throw_on_error);
}

/// <summary>
/// Delete a provider.
/// </summary>
/// <param name="key">The provider key.</param>
public void DeleteProvider(Guid key)
{
DeleteProvider(key, true);
}

/// <summary>
/// Get a provider by its key.
/// </summary>
Expand Down
Loading