NTSTATUS StreamOobCopyDataToFlatBuffer( _Inout_ STREAM_EDITOR* streamEditor, _Inout_ NET_BUFFER_LIST* netBufferListChain, size_t totalDataLength, DWORD streamFlags ) /* ++ This function copies the data described by NBL(s) into a flat buffer. It reuses the FwpsCopyStreamDataToBuffer API (via StreamCopyDataForInspection) by creating a FWPS_STREAM_DATA struct. -- */ { NTSTATUS status = STATUS_SUCCESS; FWPS_STREAM_DATA streamData = {0}; if (totalDataLength > 0) { streamData.netBufferListChain = netBufferListChain; streamData.dataLength = totalDataLength; streamData.flags = streamFlags; streamData.dataOffset.netBufferList = netBufferListChain; streamData.dataOffset.netBuffer = NET_BUFFER_LIST_FIRST_NB(streamData.dataOffset.netBufferList); streamData.dataOffset.mdl = NET_BUFFER_CURRENT_MDL(streamData.dataOffset.netBuffer); streamData.dataOffset.mdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(streamData.dataOffset.netBuffer); if (StreamCopyDataForInspection( streamEditor, &streamData ) == FALSE) { status = STATUS_NO_MEMORY; } } return status; }
void StreamInlineEdit( _Inout_ STREAM_EDITOR* streamEditor, _In_ const FWPS_INCOMING_VALUES* inFixedValues, _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, _In_ const FWPS_FILTER* filter, _In_ const FWPS_STREAM_DATA* streamData, _Inout_ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket, _Inout_ FWPS_CLASSIFY_OUT* classifyOut ) /* ++ This function implements the state machine that scans the content and computes the number of bytes to permit, bytes to block, and performs stream injection to replace the blocked data. -- */ { UINT findLength = (UINT) strlen(configStringToFind); UINT replaceLength = (UINT) strlen(configStringToReplace); if ((streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) || (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT)) { if (streamEditor->dataLength > 0) { StreamEditFlushData( streamEditor, inMetaValues->flowHandle, filter->action.calloutId, inFixedValues->layerId, streamData->flags ); streamEditor->dataLength = 0; streamEditor->dataOffset = 0; } NT_ASSERT(streamEditor->inlineEditState == INLINE_EDIT_WAITING_FOR_DATA); ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; classifyOut->actionType = FWP_ACTION_PERMIT; if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) { classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } goto Exit; } if (streamData->dataLength == 0) { ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; classifyOut->actionType = FWP_ACTION_PERMIT; if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) { classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } goto Exit; } if (streamEditor->inlineEditState != INLINE_EDIT_SKIPPING) { if ((streamData->dataLength < findLength) && !(classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA)) { ioPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA; ioPacket->countBytesRequired = findLength; classifyOut->actionType = FWP_ACTION_NONE; goto Exit; } } switch (streamEditor->inlineEditState) { case INLINE_EDIT_WAITING_FOR_DATA: { if (StreamCopyDataForInspection( streamEditor, streamData ) == FALSE) { ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION; classifyOut->actionType = FWP_ACTION_NONE; goto Exit; } // // Pass-thru to scanning // } case INLINE_EDIT_SCANNING: { UINT i; BYTE* dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset; BOOLEAN found = FALSE; for (i = 0; i < streamEditor->dataLength; ++i) { if (i + findLength <= streamEditor->dataLength) { if (RtlCompareMemory( dataStart + i, configStringToFind, findLength ) == findLength) { found = TRUE; streamEditor->inlineEditState = INLINE_EDIT_MODIFYING; if (i != 0) { ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; ioPacket->countBytesEnforced = i; classifyOut->actionType = FWP_ACTION_PERMIT; if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) { classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } streamEditor->dataOffset += i; streamEditor->dataLength -= i; break; } else { goto modify_data; } } } else { if (classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA) { break; } if (RtlCompareMemory( dataStart + i, configStringToFind, streamEditor->dataLength - i ) == streamEditor->dataLength - i) { found = TRUE; // this is a partial find ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; ioPacket->countBytesEnforced = i; classifyOut->actionType = FWP_ACTION_PERMIT; if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) { classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } RtlMoveMemory( streamEditor->scratchBuffer, dataStart + i, streamEditor->dataLength - i ); streamEditor->dataOffset = 0; streamEditor->dataLength = streamEditor->dataLength - i; streamEditor->inlineEditState = INLINE_EDIT_SKIPPING; break; } } } if (!found) { ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; ioPacket->countBytesEnforced = 0; classifyOut->actionType = FWP_ACTION_PERMIT; if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) { classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } streamEditor->dataOffset = 0; streamEditor->dataLength = 0; streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA; } break; } case INLINE_EDIT_SKIPPING: { ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; ioPacket->countBytesEnforced = 0; classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA; break; } case INLINE_EDIT_MODIFYING: modify_data: { NTSTATUS status; NET_BUFFER_LIST* netBufferList; status = FwpsAllocateNetBufferAndNetBufferList( gNetBufferListPool, 0, 0, gStringToReplaceMdl, 0, replaceLength, &netBufferList ); if (!NT_SUCCESS(status)) { ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION; classifyOut->actionType = FWP_ACTION_NONE; goto Exit; } status = FwpsStreamInjectAsync( gInjectionHandle, NULL, 0, inMetaValues->flowHandle, filter->action.calloutId, inFixedValues->layerId, streamData->flags, netBufferList, replaceLength, StreamInjectCompletionFn, NULL ); if (!NT_SUCCESS(status)) { FwpsFreeNetBufferList(netBufferList); ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION; classifyOut->actionType = FWP_ACTION_NONE; goto Exit; } ioPacket->streamAction = FWPS_STREAM_ACTION_NONE; ioPacket->countBytesEnforced = findLength; classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; streamEditor->dataOffset += findLength; streamEditor->dataLength -= findLength; if (streamEditor->dataLength > 0) { streamEditor->inlineEditState = INLINE_EDIT_SCANNING; } else { streamEditor->dataOffset = 0; streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA; } break; } default: NT_ASSERT(FALSE); break; }; Exit: return; }