void TlInspectCompletePendedConnection( _Inout_ TL_INSPECT_PENDED_PACKET** pendedConnect, _In_ BOOLEAN permitTraffic ) /* ++ This function completes the pended connection (inbound or outbound) with the inspection result. -- */ { TL_INSPECT_PENDED_PACKET* pendedConnectLocal = *pendedConnect; if (pendedConnectLocal->direction == FWP_DIRECTION_OUTBOUND) { HANDLE completionContext = pendedConnectLocal->completionContext; pendedConnectLocal->authConnectDecision = permitTraffic ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK; // // For pended ALE_AUTH_CONNECT, FwpsCompleteOperation will trigger // a re-auth during which the inspection decision is to be returned. // Here we don't remove the pended entry from the list such that the // re-auth can find it along with the recorded inspection result. // pendedConnectLocal->completionContext = NULL; FwpsCompleteOperation( completionContext, NULL ); *pendedConnect = NULL; // ownership transferred to the re-auth path. } else { if (!configPermitTraffic) { FreePendedPacket(pendedConnectLocal); *pendedConnect = NULL; } // // Permitted ALE_RECV_ACCEPT will pass thru and be processed by // TLInspectCloneReinjectInbound. FwpsCompleteOperation will be called // then when the net buffer list is cloned; after which the clone will // be recv-injected. // } }
NTSTATUS TLInspectCloneReinjectInbound( _Inout_ TL_INSPECT_PENDED_PACKET* packet ) /* ++ This function clones the inbound net buffer list and, if needed, rebuild the IP header to remove the IpSec headers and receive-injects the clone back to the tcpip stack. -- */ { NTSTATUS status = STATUS_SUCCESS; NET_BUFFER_LIST* clonedNetBufferList = NULL; NET_BUFFER* netBuffer; ULONG nblOffset; NDIS_STATUS ndisStatus; // // For inbound net buffer list, we can assume it contains only one // net buffer. // netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList); nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer); // // The TCP/IP stack could have retreated the net buffer list by the // transportHeaderSize amount; detect the condition here to avoid // retreating twice. // if (nblOffset != packet->nblOffset) { NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize); packet->transportHeaderSize = 0; } // // Adjust the net buffer list offset to the start of the IP header. // ndisStatus = NdisRetreatNetBufferDataStart( netBuffer, packet->ipHeaderSize + packet->transportHeaderSize, 0, NULL ); _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS); // // Note that the clone will inherit the original net buffer list's offset. // status = FwpsAllocateCloneNetBufferList( packet->netBufferList, NULL, NULL, 0, &clonedNetBufferList ); // // Undo the adjustment on the original net buffer list. // NdisAdvanceNetBufferDataStart( netBuffer, packet->ipHeaderSize + packet->transportHeaderSize, FALSE, NULL ); if (!NT_SUCCESS(status)) { goto Exit; } if (packet->ipSecProtected) { // // When an IpSec protected packet is indicated to AUTH_RECV_ACCEPT or // INBOUND_TRANSPORT layers, for performance reasons the tcpip stack // does not remove the AH/ESP header from the packet. And such // packets cannot be recv-injected back to the stack w/o removing the // AH/ESP header. Therefore before re-injection we need to "re-build" // the cloned packet. // status = FwpsConstructIpHeaderForTransportPacket( clonedNetBufferList, packet->ipHeaderSize, packet->addressFamily, (UINT8*)&packet->remoteAddr, (UINT8*)&packet->localAddr, packet->protocol, 0, NULL, 0, 0, NULL, 0, 0 ); if (!NT_SUCCESS(status)) { goto Exit; } } if (packet->completionContext != NULL) { NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET); FwpsCompleteOperation( packet->completionContext, clonedNetBufferList ); packet->completionContext = NULL; } status = FwpsInjectTransportReceiveAsync( gInjectionHandle, NULL, NULL, 0, packet->addressFamily, packet->compartmentId, packet->interfaceIndex, packet->subInterfaceIndex, clonedNetBufferList, TLInspectInjectComplete, packet ); if (!NT_SUCCESS(status)) { goto Exit; } clonedNetBufferList = NULL; // ownership transferred to the // completion function. Exit: if (clonedNetBufferList != NULL) { FwpsFreeCloneNetBufferList(clonedNetBufferList, 0); } return status; }
_IRQL_requires_same_ inline VOID KrnlHlprPendDataPurge(_Inout_ PEND_DATA* pPendData) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> KrnlHlprPendDataPurge()\n"); #endif /// DBG NT_ASSERT(pPendData); #if(NTDDI_VERSION >= NTDDI_WIN7) if(pPendData->layerID == FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4 || pPendData->layerID == FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6) { if(pPendData->classifyHandle && pPendData->isPended) { FwpsCompleteClassify(pPendData->classifyHandle, 0, &(pPendData->classifyOut)); FwpsReleaseClassifyHandle(pPendData->classifyHandle); pPendData->classifyHandle = 0; pPendData->pPCPendData = 0; pPendData->isPended = FALSE; } } else #endif /// (NTDDI_VERSION >= NTDDI_WIN7) { if(pPendData->completionContext && pPendData->isPended) { FwpsCompleteOperation(pPendData->completionContext, pPendData->pNBL); pPendData->completionContext = 0; pPendData->pNBL = 0; pPendData->pPendAuthorizationData = 0; pPendData->isPended = FALSE; } } RtlZeroMemory(pPendData, sizeof(PEND_DATA)); #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- KrnlHlprPendDataPurge()\n"); #endif /// DBG return; }