it does http/https redirection based on a database of urls…i have the https part commented out for now, until i get this fixed…
my classify function…basically, when a new flow is made, i make sure the HTTP header is completed…then I cloned the packet and block, and it gets reinjected inside of the worker thread…
when data is inbound, i just block and reinject it inline…
#if(NTDDI_VERSION < NTDDI_WIN7)
VOID NTAPI
ClassifyFn(
IN const FWPS_INCOMING_VALUES *inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES *inMetaValues,
IN OUT VOID *layerData,
IN const FWPS_FILTER *filter,
IN UINT64 flowContext,
IN OUT FWPS_CLASSIFY_OUT *classifyOut
)
#elseif(NTDDI_VERSION == NTDDI_WIN7)
void NTAPI ClassifyFn(
In const FWPS_INCOMING_VALUES0 *inFixedValues,
In const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
Inout void *layerData,
In_opt const void *classifyContext,
In const FWPS_FILTER1 *filter,
In UINT64 flowContext,
Inout FWPS_CLASSIFY_OUT0 *classifyOut
)
#else
void NTAPI ClassifyFn(
In const FWPS_INCOMING_VALUES0 *inFixedValues,
In const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
Inout_opt void *layerData,
In_opt const void *classifyContext,
In const FWPS_FILTER2 *filter,
In UINT64 flowContext,
Inout FWPS_CLASSIFY_OUT0 *classifyOut
)
#endif
{
UNREFERENCED_PARAMETER(inFixedValues);
UNREFERENCED_PARAMETER(filter);
UNREFERENCED_PARAMETER(flowContext);
UNREFERENCED_PARAMETER(classifyOut);
//PAGED_CODE();
//DebugTrace(“%s Entry”, FUNCTION);
classifyOut->actionType = FWP_ACTION_PERMIT;
FWPS_STREAM_CALLOUT_IO_PACKET *calloutPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*)layerData;
calloutPacket->streamAction = FWPS_STREAM_ACTION_NONE;
calloutPacket->countBytesRequired = 0;
calloutPacket->countBytesEnforced = calloutPacket->streamData->dataLength;
if (IsDriverUnloading) {
if (!flowContext) {
return;
}
NET_BUFFER_LIST *clonedNetBufferList = NULL;
NTSTATUS s = FwpsCloneStreamData(calloutPacket->streamData, NULL, NULL, 0, &clonedNetBufferList);
if (s != STATUS_SUCCESS) {
DebugTrace(“FwpsAllocateCloneNetBufferList failed”);
return;
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, “injecting data with flow id[%ld] layer id[%d] length[%ld]\r\n”, inMetaValues->flowHandle, inFixedValues->layerId,
calloutPacket->streamData->dataLength);
FwpsStreamInjectAsync(gInjectionHandle, NULL, 0, inMetaValues->flowHandle, CalloutId, inFixedValues->layerId, calloutPacket->streamData->flags,
clonedNetBufferList, calloutPacket->streamData->dataLength, PacketClonedInjectionCompletion, NULL);
classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->flags = FWPS_CLASSIFY_OUT_FLAG_ABSORB;
return;
}
if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0) {
//DebugTrace(“%s Exit”, FUNCTION);
return;
}
if (!calloutPacket->streamData->dataLength) {
return;
}
PFLOWPACKET pFlowPacket = NULL;
if (!flowContext) {
pFlowPacket = (PFLOWPACKET)ExAllocateFromNPagedLookasideList(&HttpFlowLookList);
if (!pFlowPacket) {
return;
}
pFlowPacket->flowId = inMetaValues->flowHandle;
pFlowPacket->stopThread = 0;
pFlowPacket->flowDeleted = 0;
pFlowPacket->permitPacket = 0;
pFlowPacket->allowPacket = 0;
pFlowPacket->queueInjectionPackets = CQueueCreate();
pFlowPacket->hPkThread = NULL;
pFlowPacket->foundHeader = 0;
//MHashMapInsert(PHashMapHTTPFlows, pFlowPacket->flowId, (void*)pFlowPacket);
NTSTATUS ntStatus = FwpsFlowAssociateContext(pFlowPacket->flowId, FWPS_LAYER_STREAM_V4, CalloutId, (UINT64)pFlowPacket);
if (ntStatus != STATUS_SUCCESS) {
DebugTrace(“FwpsFlowAssociateContext failed for HTTP.”);
//MHashMapRemoveByKey(PHashMapHTTPFlows, pFlowPacket->flowId);
ExFreeToNPagedLookasideList(&HttpFlowLookList, pFlowPacket);
return;
}
else {
PFLOWTHREADPACKET p = (PFLOWTHREADPACKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(FLOWTHREADPACKET), POOLTAGDRIVER);
p->flowId = inMetaValues->flowHandle;
p->queueInjectionPackets = pFlowPacket->queueInjectionPackets;
p->stopThread = 0;
CQueueAddRef(pFlowPacket->queueInjectionPackets);
CQueuePush(QueueHTTPFlowPackets, (void*)p);
KeSetEvent(&KEventNewHTTPFlow, 0, FALSE);
pFlowPacket->threadPacket = p;
}
}
else {
//DebugTrace(“got flow context…”);
pFlowPacket = (PFLOWPACKET)flowContext;
}
if (pFlowPacket->permitPacket) {
return;
}
if (pFlowPacket->foundHeader) {
//DebugTrace(“header found for[%s]…”, pFlowPacket->currentUrl);
//DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, “injecting data with flow id[%ld] layer id[%d] length[%ld]\r\n”, inMetaValues->flowHandle, inFixedValues->layerId,
//calloutPacket->streamData->dataLength);
for (NET_BUFFER_LIST* pCurrentNBL = calloutPacket->streamData->netBufferListChain; pCurrentNBL;) {
NET_BUFFER_LIST* pNextNBL = NET_BUFFER_LIST_NEXT_NBL(pCurrentNBL);
FwpsReferenceNetBufferList(pCurrentNBL, FALSE);
pCurrentNBL = pNextNBL;
}
NET_BUFFER_LIST *clonedNetBufferList = NULL;
NTSTATUS s = FwpsCloneStreamData(calloutPacket->streamData, NULL, NULL, 0, &clonedNetBufferList);
if (s != STATUS_SUCCESS) {
DebugTrace(“FwpsCloneStreamData failed”);
return;
}
s = FwpsStreamInjectAsync(gInjectionHandle, NULL, 0, inMetaValues->flowHandle, CalloutId, inFixedValues->layerId, calloutPacket->streamData->flags,
clonedNetBufferList, calloutPacket->streamData->dataLength, PacketClonedInjectionCompletion2, NULL);
if (s != STATUS_SUCCESS) {
FwpsFreeNetBufferList(clonedNetBufferList);
}
classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
classifyOut->rights &= ~(UINT32)FWPS_RIGHT_ACTION_WRITE;
DebugTrace(“%s Exit”, FUNCTION);
return;
}
char* stream = (char*)ExAllocatePoolWithTag(NonPagedPool, calloutPacket->streamData->dataLength, POOL_TAG_CALLOUT_STREAM);
if (!stream) {
return;
}
SIZE_T streamBytesCopied = 0;
FwpsCopyStreamDataToBuffer(calloutPacket->streamData, stream, calloutPacket->streamData->dataLength, &streamBytesCopied);
if (streamBytesCopied != calloutPacket->streamData->dataLength) {
DebugTrace(“streamBytesCopied != streamLength”);
ExFreePoolWithTag(stream, POOL_TAG_CALLOUT_STREAM);
return;
}
if (!(stream[0] == ‘G’ && stream[1] == ‘E’ && stream[2] == ‘T’)) {
pFlowPacket->permitPacket = 1;
//KeSetEvent(&pFlowPacket->threadPacket->eventQueue, 0, FALSE);
ExFreePoolWithTag(stream, POOL_TAG_CALLOUT_STREAM);
DebugTrace(“GET not found…”);
calloutPacket->streamAction = FWPS_STREAM_ACTION_ALLOW_CONNECTION;
return;
}
for (int loopa = ((int)streamBytesCopied)-1; loopa >= 0; loopa–) {
if ((loopa - 3) < 0) {
DebugTrace(“need more data…”);
calloutPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
calloutPacket->countBytesRequired = (UINT32)streamBytesCopied + 1;
classifyOut->actionType = FWP_ACTION_NONE;
ExFreePoolWithTag(stream, POOL_TAG_CALLOUT_STREAM);
return;
}
if (stream[loopa] == ‘\n’) {
if (stream[loopa - 1] == ‘\r’) {
if (stream[loopa - 2] == ‘\n’) {
if (stream[loopa - 3] == ‘\r’) {
pFlowPacket->foundHeader = 1;
break;
}
}
}
}
}
if (!pFlowPacket->foundHeader) {
DebugTrace(“header not found, need more data”);
calloutPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
classifyOut->actionType = FWP_ACTION_NONE;
calloutPacket->countBytesRequired = (UINT32)streamBytesCopied + 1;
ExFreePoolWithTag(stream, POOL_TAG_CALLOUT_STREAM);
return;
}
for (NET_BUFFER_LIST* pCurrentNBL = calloutPacket->streamData->netBufferListChain; pCurrentNBL;) {
NET_BUFFER_LIST* pNextNBL = NET_BUFFER_LIST_NEXT_NBL(pCurrentNBL);
FwpsReferenceNetBufferList(pCurrentNBL, FALSE);
pCurrentNBL = pNextNBL;
}
NET_BUFFER_LIST *clonedNetBufferList = NULL;
NTSTATUS s = FwpsCloneStreamData(calloutPacket->streamData, NULL, NULL, 0, &clonedNetBufferList);
if (s != STATUS_SUCCESS) {
DebugTrace(“FwpsAllocateCloneNetBufferList failed”);
ExFreePoolWithTag(stream, POOL_TAG_CALLOUT_STREAM);
return;
}
PINJECTION_PACKET pInjectionPacket = (PINJECTION_PACKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(INJECTION_PACKET), ‘eee’);
if (!pInjectionPacket) {
ExFreePoolWithTag(stream, POOL_TAG_CALLOUT_STREAM);
return;
}
pInjectionPacket->data = stream;
pInjectionPacket->data_length = calloutPacket->streamData->dataLength;
pInjectionPacket->flow_id = inMetaValues->flowHandle;
pInjectionPacket->layerId = inFixedValues->layerId;
pInjectionPacket->clonedNetBufferList = clonedNetBufferList;
pInjectionPacket->streamFlags = calloutPacket->streamData->flags;
CQueuePush(pFlowPacket->queueInjectionPackets, (void*)pInjectionPacket);
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, “queueing data with flow id[%ld] layer id[%d] length[%ld]\r\n”, inMetaValues->flowHandle, inFixedValues->layerId,
calloutPacket->streamData->dataLength);
KeSetEvent(&(pFlowPacket->queueInjectionPackets->eventQueue), 0, FALSE);
classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
classifyOut->rights &= ~(UINT32)FWPS_RIGHT_ACTION_WRITE;
//DebugTrace(“%s Exit”, FUNCTION);
}