I have created an application in which GUI is connected to the driver which is performing some network data inspection. I created two callouts: on V4 Stream Layer and ALE_ESTABLISHED Layer. What is weird is that my program doesn't go into this if statement at all (I'm checking if "I'm here" is showing up in kernel debugger):
static void ProcessStreamData(
const FWPS_INCOMING_VALUES0* inFixedValues,
const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
void* layerData,
FWPS_CLASSIFY_OUT0* classifyOut)
{
KIRQL oldIrql;
KeAcquireSpinLock(&ConnectionLock, &oldIrql);
FWPS_STREAM_CALLOUT_IO_PACKET0* ioPacket = (FWPS_STREAM_CALLOUT_IO_PACKET0*)layerData;
FWPS_STREAM_DATA0* streamData = ioPacket->streamData;
WCHAR* ProcessName = L"unknown";
ULONGLONG ProcessId = (ULONGLONG)inMetaValues->processId;
UINT32 LocalIp = inFixedValues->incomingValue[FWPS_FIELD_STREAM_V4_IP_LOCAL_ADDRESS].value.uint32;
UINT32 RemoteIp = inFixedValues->incomingValue[FWPS_FIELD_STREAM_V4_IP_REMOTE_ADDRESS].value.uint32;
UINT16 LocalPort = inFixedValues->incomingValue[FWPS_FIELD_STREAM_V4_IP_LOCAL_PORT].value.uint16;
UINT16 RemotePort = inFixedValues->incomingValue[FWPS_FIELD_STREAM_V4_IP_REMOTE_PORT].value.uint16;
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
ConnectionInfo connection = g_Connections[i];
if (connection.ProcessId == ProcessId && connection.LocalIp == LocalIp && connection.RemoteIp == RemoteIp && connection.LocalPort == LocalPort && connection.RemotePort == RemotePort)
{
KdPrint(("I'm here"));
if (streamData->flags == FWPS_STREAM_FLAG_RECEIVE) {
g_Connections[i].BytesReceived += streamData->dataLength;
}
else if (streamData->flags == FWPS_STREAM_FLAG_SEND) {
g_Connections[i].BytesSent += streamData->dataLength;
}
}
}
KeReleaseSpinLock(&ConnectionLock, oldIrql);
}
This is called from StreamCalloutConnectClassifyFn:
static void StreamCalloutConnectClassifyFn(
const FWPS_INCOMING_VALUES0* inFixedValues,
const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
void* layerData,
const FWPS_FILTER0* filter,
UINT64 /*flowContext*/,
FWPS_CLASSIFY_OUT0* classifyOut)
{
// Allowing the traffic for another filter to make a final decision.
if (FlagOn(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE))
{
classifyOut->actionType = FWP_ACTION_CONTINUE;
}
ProcessStreamData(inFixedValues, inMetaValues, layerData, classifyOut);
// Callout function should clear the FWPS_RIGHT_ACTION_WRITE flag when it returns FWP_ACTION_BLOCK for the suggested action
// and if FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT flag is set
if (FWP_ACTION_BLOCK == classifyOut->actionType || FlagOn(filter->flags, FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT))
{
ClearFlag(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE);
}
}
And this is called from Initialize Callout:
static NTSTATUS InitializeCallout(PDEVICE_OBJECT deviceObject)
{
/*FWPM_SUBLAYER subLayer = {};
subLayer.displayData.name = const_cast<wchar_t*>(L"TcpInterception Sub-Layer");
subLayer.subLayerKey = TCP_INTERCEPTION_SUBLAYER;*/
/* NTSTATUS status = FwpmSubLayerAdd(g_engineHandle, &subLayer, nullptr);*/
NTSTATUS status;
FWPS_CALLOUT0 sCallout =
{
TCP_INTERCEPTION_TRANSPORT_V4_CALLOUT, // calloutKey
0, // flags
CalloutConnectClassifyFn, // classifyFn
CalloutNotifyFn, // notifyFn
FlowDeleteNotifyFn // flowDeleteFn
};
status = FwpsCalloutRegister0(deviceObject, &sCallout, &g_id);
if (!NT_SUCCESS(status))
{
return status;
}
FWPM_CALLOUT mCallout = {};
mCallout.calloutKey = TCP_INTERCEPTION_TRANSPORT_V4_CALLOUT;
mCallout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
mCallout.displayData.name = const_cast<wchar_t*>(g_displayName);
status = FwpmCalloutAdd(g_engineHandle, &mCallout, nullptr, nullptr);
if (!NT_SUCCESS(status))
{
return status;
}
FWPS_CALLOUT0 StreamCallout =
{
STREAM_V4_CALLOUT,
0,
StreamCalloutConnectClassifyFn,
StreamCalloutNotifyFn,
StreamFlowDeleteNotifyFn
};
status = FwpsCalloutRegister0(deviceObject, &StreamCallout, &g_StreamId);
if (!NT_SUCCESS(status))
{
return status;
}
FWPM_CALLOUT mStreamCallout = {};
mStreamCallout.calloutKey = STREAM_V4_CALLOUT;
mStreamCallout.applicableLayer = FWPM_LAYER_STREAM_V4;
mStreamCallout.displayData.name = const_cast<wchar_t*>(g_displayNameStream);
status = FwpmCalloutAdd(g_engineHandle, &mStreamCallout, nullptr, nullptr);
if (!NT_SUCCESS(status))
{
return status;
}
/* Add Filter for TCP only*/
FWPM_FILTER_CONDITION filterCondition = {};
filterCondition.fieldKey = FWPM_CONDITION_IP_PROTOCOL;
filterCondition.matchType = FWP_MATCH_EQUAL;
filterCondition.conditionValue.type = FWP_UINT8;
filterCondition.conditionValue.uint16 = IPPROTO_TCP;
FWPM_FILTER filter = {};
filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
filter.displayData.name = const_cast<wchar_t*>(g_displayName);;
filter.displayData.description = filter.displayData.name;
filter.action.type = FWP_ACTION_CALLOUT_INSPECTION;
filter.action.calloutKey = TCP_INTERCEPTION_TRANSPORT_V4_CALLOUT;
filter.filterCondition = &filterCondition;
filter.numFilterConditions = 1;
filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
filter.weight.type = FWP_EMPTY;
status = FwpmFilterAdd(g_engineHandle, &filter, NULL, NULL);
if (!NT_SUCCESS(status))
{
return status;
}
FWPM_FILTER Streamfilter = {};
Streamfilter.layerKey = FWPM_LAYER_STREAM_V4;
Streamfilter.displayData.name = const_cast<wchar_t*>(g_displayName);;
Streamfilter.displayData.description = Streamfilter.displayData.name;
Streamfilter.action.type = FWP_ACTION_CALLOUT_INSPECTION;
Streamfilter.action.calloutKey = STREAM_V4_CALLOUT;
Streamfilter.filterCondition = 0;
Streamfilter.numFilterConditions = 0;
Streamfilter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
Streamfilter.weight.type = FWP_EMPTY;
status = FwpmFilterAdd(g_engineHandle, &Streamfilter, NULL, NULL);
if (!NT_SUCCESS(status))
{
return status;
}
return status;
}
Does anyone have suggestions?