Move RewriteBind()

This commit is contained in:
Odd Stranne
2021-02-26 17:59:17 +01:00
parent 4c8a39f8ce
commit b5489d2d2f
3 changed files with 169 additions and 182 deletions

View File

@@ -2,9 +2,9 @@
#include "firewall.h"
#include "context.h"
#include "identifiers.h"
#include "filters.h" // TODO-NOW: Correct this, since its only for RewriteBind()
#include "asyncbind.h"
#include "callouts.h"
#include "../util.h"
namespace firewall
{
@@ -82,6 +82,174 @@ RegisterCalloutTx
return FwpsCalloutRegister1(DeviceObject, &aCallout, NULL);
}
//
// RewriteBind()
//
// This is where the splitting happens.
// Move socket binds from tunnel interface to the internet connected interface.
//
void
RewriteBind
(
CONTEXT *Context,
const FWPS_INCOMING_VALUES0 *FixedValues,
const FWPS_INCOMING_METADATA_VALUES0 *MetaValues,
UINT64 FilterId,
const void *ClassifyContext,
FWPS_CLASSIFY_OUT0 *ClassifyOut
)
{
UNREFERENCED_PARAMETER(MetaValues);
UINT64 classifyHandle = 0;
auto status = FwpsAcquireClassifyHandle0
(
const_cast<void*>(ClassifyContext),
0,
&classifyHandle
);
if (!NT_SUCCESS(status))
{
DbgPrint("FwpsAcquireClassifyHandle0() failed 0x%X\n", status);
return;
}
FWPS_BIND_REQUEST0 *bindRequest = NULL;
status = FwpsAcquireWritableLayerDataPointer0
(
classifyHandle,
FilterId,
0,
(PVOID*)&bindRequest,
ClassifyOut
);
if (!NT_SUCCESS(status))
{
DbgPrint("FwpsAcquireWritableLayerDataPointer0() failed 0x%X\n", status);
goto Cleanup_handle;
}
//
// According to documentation, FwpsAcquireWritableLayerDataPointer0() will update the
// `actionType` and `rights` fields with poorly chosen values:
//
// ```
// classifyOut->actionType = FWP_ACTION_BLOCK
// classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE
// ```
//
// However, in practice it seems to not make any changes to those fields.
// But if it did we'd want to ensure the fields have sane values.
//
ClassifyOut->actionType = FWP_ACTION_CONTINUE;
ClassifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
//
// There's a list with redirection history.
//
// This only ever comes into play if several callouts are fighting to redirect the bind.
//
// To prevent recursion, we need to check if we're on the list, and abort if so.
//
for (auto history = bindRequest->previousVersion;
history != NULL;
history = history->previousVersion)
{
if (history->modifierFilterId == FilterId)
{
DbgPrint("Aborting bind processing because already redirected by us\n");
goto Cleanup_data;
}
}
//
// Rewrite bind as applicable.
//
const bool ipv4 = FixedValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4;
WdfWaitLockAcquire(Context->IpAddresses.Lock, NULL);
if (ipv4)
{
auto bindTarget = (SOCKADDR_IN*)&(bindRequest->localAddressAndPort);
DbgPrint("Bind request eligible for splitting: %d.%d.%d.%d:%d\n",
bindTarget->sin_addr.S_un.S_un_b.s_b1,
bindTarget->sin_addr.S_un.S_un_b.s_b2,
bindTarget->sin_addr.S_un.S_un_b.s_b3,
bindTarget->sin_addr.S_un.S_un_b.s_b4,
ntohs(bindTarget->sin_port)
);
if (IN4_IS_ADDR_UNSPECIFIED(&(bindTarget->sin_addr))
|| IN4_ADDR_EQUAL(&(bindTarget->sin_addr), &(Context->IpAddresses.Addresses.TunnelIpv4)))
{
DbgPrint("SPLITTING\n");
bindTarget->sin_addr = Context->IpAddresses.Addresses.InternetIpv4;
ClassifyOut->actionType = FWP_ACTION_PERMIT;
ClassifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
}
}
else
{
auto bindTarget = (SOCKADDR_IN6*)&(bindRequest->localAddressAndPort);
DbgPrint("Bind request eligible for splitting: [%X:%X:%X:%X:%X:%X:%X:%X]:%d\n",
ntohs(bindTarget->sin6_addr.u.Word[0]),
ntohs(bindTarget->sin6_addr.u.Word[1]),
ntohs(bindTarget->sin6_addr.u.Word[2]),
ntohs(bindTarget->sin6_addr.u.Word[3]),
ntohs(bindTarget->sin6_addr.u.Word[4]),
ntohs(bindTarget->sin6_addr.u.Word[5]),
ntohs(bindTarget->sin6_addr.u.Word[6]),
ntohs(bindTarget->sin6_addr.u.Word[7]),
ntohs(bindTarget->sin6_port)
);
static const IN6_ADDR IN6_ADDR_ANY = { 0 };
if (IN6_ADDR_EQUAL(&(bindTarget->sin6_addr), &IN6_ADDR_ANY)
|| IN6_ADDR_EQUAL(&(bindTarget->sin6_addr), &(Context->IpAddresses.Addresses.TunnelIpv6)))
{
DbgPrint("SPLITTING\n");
bindTarget->sin6_addr = Context->IpAddresses.Addresses.InternetIpv6;
ClassifyOut->actionType = FWP_ACTION_PERMIT;
ClassifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
}
}
WdfWaitLockRelease(Context->IpAddresses.Lock);
Cleanup_data:
//
// Call the "apply" function even in instances where we've made no changes
// to the data, because it was deemed not necessary, or aborting for some other reason.
//
// This is the correct logic according to documentation.
//
FwpsApplyModifiedLayerData0(classifyHandle, (PVOID*)&bindRequest, 0);
Cleanup_handle:
FwpsReleaseClassifyHandle0(classifyHandle);
}
void
ClassifyUnknownBind
(

View File

@@ -6,174 +6,6 @@
namespace firewall
{
//
// RewriteBind()
//
// This is where the splitting happens.
// Move socket binds from tunnel interface to the internet connected interface.
//
void
RewriteBind
(
CONTEXT *Context,
const FWPS_INCOMING_VALUES0 *FixedValues,
const FWPS_INCOMING_METADATA_VALUES0 *MetaValues,
UINT64 FilterId,
const void *ClassifyContext,
FWPS_CLASSIFY_OUT0 *ClassifyOut
)
{
UNREFERENCED_PARAMETER(MetaValues);
UINT64 classifyHandle = 0;
auto status = FwpsAcquireClassifyHandle0
(
const_cast<void*>(ClassifyContext),
0,
&classifyHandle
);
if (!NT_SUCCESS(status))
{
DbgPrint("FwpsAcquireClassifyHandle0() failed 0x%X\n", status);
return;
}
FWPS_BIND_REQUEST0 *bindRequest = NULL;
status = FwpsAcquireWritableLayerDataPointer0
(
classifyHandle,
FilterId,
0,
(PVOID*)&bindRequest,
ClassifyOut
);
if (!NT_SUCCESS(status))
{
DbgPrint("FwpsAcquireWritableLayerDataPointer0() failed 0x%X\n", status);
goto Cleanup_handle;
}
//
// According to documentation, FwpsAcquireWritableLayerDataPointer0() will update the
// `actionType` and `rights` fields with poorly chosen values:
//
// ```
// classifyOut->actionType = FWP_ACTION_BLOCK
// classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE
// ```
//
// However, in practice it seems to not make any changes to those fields.
// But if it did we'd want to ensure the fields have sane values.
//
ClassifyOut->actionType = FWP_ACTION_CONTINUE;
ClassifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
//
// There's a list with redirection history.
//
// This only ever comes into play if several callouts are fighting to redirect the bind.
//
// To prevent recursion, we need to check if we're on the list, and abort if so.
//
for (auto history = bindRequest->previousVersion;
history != NULL;
history = history->previousVersion)
{
if (history->modifierFilterId == FilterId)
{
DbgPrint("Aborting bind processing because already redirected by us\n");
goto Cleanup_data;
}
}
//
// Rewrite bind as applicable.
//
const bool ipv4 = FixedValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4;
WdfWaitLockAcquire(Context->IpAddresses.Lock, NULL);
if (ipv4)
{
auto bindTarget = (SOCKADDR_IN*)&(bindRequest->localAddressAndPort);
DbgPrint("Bind request eligible for splitting: %d.%d.%d.%d:%d\n",
bindTarget->sin_addr.S_un.S_un_b.s_b1,
bindTarget->sin_addr.S_un.S_un_b.s_b2,
bindTarget->sin_addr.S_un.S_un_b.s_b3,
bindTarget->sin_addr.S_un.S_un_b.s_b4,
ntohs(bindTarget->sin_port)
);
if (IN4_IS_ADDR_UNSPECIFIED(&(bindTarget->sin_addr))
|| IN4_ADDR_EQUAL(&(bindTarget->sin_addr), &(Context->IpAddresses.Addresses.TunnelIpv4)))
{
DbgPrint("SPLITTING\n");
bindTarget->sin_addr = Context->IpAddresses.Addresses.InternetIpv4;
ClassifyOut->actionType = FWP_ACTION_PERMIT;
ClassifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
}
}
else
{
auto bindTarget = (SOCKADDR_IN6*)&(bindRequest->localAddressAndPort);
DbgPrint("Bind request eligible for splitting: [%X:%X:%X:%X:%X:%X:%X:%X]:%d\n",
ntohs(bindTarget->sin6_addr.u.Word[0]),
ntohs(bindTarget->sin6_addr.u.Word[1]),
ntohs(bindTarget->sin6_addr.u.Word[2]),
ntohs(bindTarget->sin6_addr.u.Word[3]),
ntohs(bindTarget->sin6_addr.u.Word[4]),
ntohs(bindTarget->sin6_addr.u.Word[5]),
ntohs(bindTarget->sin6_addr.u.Word[6]),
ntohs(bindTarget->sin6_addr.u.Word[7]),
ntohs(bindTarget->sin6_port)
);
static const IN6_ADDR IN6_ADDR_ANY = { 0 };
if (IN6_ADDR_EQUAL(&(bindTarget->sin6_addr), &IN6_ADDR_ANY)
|| IN6_ADDR_EQUAL(&(bindTarget->sin6_addr), &(Context->IpAddresses.Addresses.TunnelIpv6)))
{
DbgPrint("SPLITTING\n");
bindTarget->sin6_addr = Context->IpAddresses.Addresses.InternetIpv6;
ClassifyOut->actionType = FWP_ACTION_PERMIT;
ClassifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
}
}
WdfWaitLockRelease(Context->IpAddresses.Lock);
Cleanup_data:
//
// Call the "apply" function even in instances where we've made no changes
// to the data, because it was deemed not necessary, or aborting for some other reason.
//
// This is the correct logic according to documentation.
//
FwpsApplyModifiedLayerData0(classifyHandle, (PVOID*)&bindRequest, 0);
Cleanup_handle:
FwpsReleaseClassifyHandle0(classifyHandle);
}
NTSTATUS
RegisterFilterBindRedirectIpv4Tx
(

View File

@@ -6,19 +6,6 @@
namespace firewall
{
// TODO-NOW Move this out to some place more suitable
// Perhaps its own implementation file
void
RewriteBind
(
CONTEXT *Context,
const FWPS_INCOMING_VALUES0 *FixedValues,
const FWPS_INCOMING_METADATA_VALUES0 *MetaValues,
UINT64 FilterId,
const void *ClassifyContext,
FWPS_CLASSIFY_OUT0 *ClassifyOut
);
//
// RegisterFilterBindRedirectIpv4Tx()
//