PWSK_SOCKET NTAPI WSKCreateSocket( IN ADDRESS_FAMILY AddressFamily, IN USHORT SocketType, IN ULONG Protocol, IN ULONG Flags ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; PWSK_SOCKET WskSocket = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; TRACE_ENTER(); if (g_SocketsState != INITIALIZED) { TRACE_EXIT(); return NULL; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCreateSocket()::InitWskData() failed with status 0x%08X\n", Status); TRACE_EXIT(); return NULL; } Status = g_WskProvider.Dispatch->WskSocket( g_WskProvider.Client, AddressFamily, SocketType, Protocol, Flags, NULL, NULL, NULL, NULL, NULL, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); Status = Irp->IoStatus.Status; } if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCreateSocket()::Dispatch::WskSocket() failed with status 0x%08X\n", Status); } WskSocket = NT_SUCCESS(Status) ? (PWSK_SOCKET)Irp->IoStatus.Information : NULL; IoFreeIrp(Irp); TRACE_EXIT(); return (PWSK_SOCKET)WskSocket; }
NTSTATUS NTAPI WSKSendPacketInternal_NBL( IN BOOLEAN bIPv4, IN PNET_BUFFER_LIST NetBufferList, IN ULONG Offset ) { NTSTATUS status = STATUS_SUCCESS; ULONG SentBytes; TRACE_ENTER(); SentBytes = bIPv4 ? WSKSendTo_NBL(g_IPv4Socket, NetBufferList, Offset, (PSOCKADDR)& g_IPv4RemoteAddress) : WSKSendTo_NBL(g_IPv6Socket, NetBufferList, Offset, (PSOCKADDR)& g_IPv6RemoteAddress); if (SentBytes != NetBufferList->FirstNetBuffer->DataLength - Offset) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendPacketInternal_NBL()::WSKSendTo_NBL() failed with SentBytes 0x%08X\n", SentBytes); } TRACE_EXIT(); return status; }
BOOLEAN NPF_IsPacketSelfSent( _In_ PNET_BUFFER_LIST pNetBufferList, _In_ BOOLEAN bIPv4 ) { NTSTATUS status = STATUS_SUCCESS; NET_BUFFER* pNetBuffer = 0; PVOID pContiguousData = NULL; UCHAR pPacketData[IPV6_HDR_LEN]; UCHAR iProtocol; TRACE_ENTER(); pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); while (pNetBuffer) { pContiguousData = NdisGetDataBuffer(pNetBuffer, bIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN, pPacketData, 1, 0); if (!pContiguousData) { status = STATUS_UNSUCCESSFUL; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_IsPacketSelfSent: NdisGetDataBuffer() [status: %#x]\n", status); TRACE_EXIT(); return FALSE; } else { iProtocol = bIPv4 ? ((PIP_HEADER) pContiguousData)->ip_Protocol : ((PIP6_HEADER) pContiguousData)->ip6_CTL.ip6_HeaderCtl.ip6_NextHeader; if (iProtocol == IPPROTO_NPCAP_LOOPBACK) { TRACE_EXIT(); return TRUE; } else { TRACE_EXIT(); return FALSE; } } pNetBuffer = pNetBuffer->Next; } TRACE_EXIT(); return FALSE; }
NTSTATUS NTAPI WSKCloseSocket( IN PWSK_SOCKET WskSocket ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; TRACE_ENTER(); if (g_SocketsState != INITIALIZED || !WskSocket) { TRACE_EXIT(); return STATUS_INVALID_PARAMETER; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCloseSocket()::InitWskData() failed with status 0x%08X\n", Status); TRACE_EXIT(); return Status; } Status = ((PWSK_PROVIDER_BASIC_DISPATCH)WskSocket->Dispatch)->WskCloseSocket(WskSocket, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); Status = Irp->IoStatus.Status; } else if (Status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKCloseSocket()::Dispatch::WskSocket() failed with status 0x%08X\n", Status); } IoFreeIrp(Irp); TRACE_EXIT(); return Status; }
NTSTATUS NTAPI NPF_WSKStartup( ) { WSK_CLIENT_NPI WskClient = {0}; NTSTATUS Status = STATUS_UNSUCCESSFUL; TRACE_ENTER(); if (InterlockedCompareExchange(&g_SocketsState, INITIALIZING, DEINITIALIZED) != DEINITIALIZED) return STATUS_ALREADY_REGISTERED; WskClient.ClientContext = NULL; WskClient.Dispatch = &g_WskDispatch; Status = WskRegister(&WskClient, &g_WskRegistration); if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKStartup()::WskRegister() failed with status 0x%08X\n", Status); InterlockedExchange(&g_SocketsState, DEINITIALIZED); TRACE_EXIT(); return Status; } Status = WskCaptureProviderNPI(&g_WskRegistration, WSK_NO_WAIT, &g_WskProvider); if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKStartup()::WskCaptureProviderNPI() failed with status 0x%08X\n", Status); WskDeregister(&g_WskRegistration); InterlockedExchange(&g_SocketsState, DEINITIALIZED); TRACE_EXIT(); return Status; } InterlockedExchange(&g_SocketsState, INITIALIZED); TRACE_EXIT(); return STATUS_SUCCESS; }
static NTSTATUS InitWskBuffer_NBL( IN PNET_BUFFER_LIST NetBufferList, IN ULONG BufferOffset, OUT PWSK_BUF WskBuffer ) { NTSTATUS Status = STATUS_SUCCESS; TRACE_ENTER(); ASSERT(NetBufferList); ASSERT(WskBuffer); WskBuffer->Offset = BufferOffset; WskBuffer->Length = NetBufferList->FirstNetBuffer->DataLength - BufferOffset; WskBuffer->Mdl = NetBufferList->FirstNetBuffer->CurrentMdl; if (!WskBuffer->Mdl) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "InitWskBuffer_NBL()::NetBufferList->FirstNetBuffer->CurrentMdl failed with status 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES); TRACE_EXIT(); return STATUS_INSUFFICIENT_RESOURCES; } __try { if ((WskBuffer->Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) != MDL_MAPPED_TO_SYSTEM_VA && (WskBuffer->Mdl->MdlFlags & MDL_PAGES_LOCKED) != MDL_PAGES_LOCKED && (WskBuffer->Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) != MDL_SOURCE_IS_NONPAGED_POOL) { MmProbeAndLockPages(WskBuffer->Mdl, KernelMode, IoWriteAccess); } } __except (EXCEPTION_EXECUTE_HANDLER) { TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "InitWskBuffer_NBL()::MmProbeAndLockPages(%p) failed with status 0x%08X\n", WskBuffer->Mdl, STATUS_ACCESS_VIOLATION); Status = STATUS_ACCESS_VIOLATION; } TRACE_EXIT(); return Status; }
VOID NPF_CloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status) { POPEN_INSTANCE Open; PIRP Irp; TRACE_ENTER(); Open = (POPEN_INSTANCE)ProtocolBindingContext; ASSERT(Open != NULL); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", Open); NdisSetEvent(&Open->NdisOpenCloseCompleteEvent); TRACE_EXIT(); return; }
VOID NPF_NetworkInjectionComplete( _In_ VOID* pContext, _Inout_ NET_BUFFER_LIST* pNetBufferList, _In_ BOOLEAN dispatchLevel ) { UNREFERENCED_PARAMETER(dispatchLevel); TRACE_ENTER(); if (pNetBufferList->Status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkInjectionComplete: pNetBufferList->Status [status: %#x]\n", pNetBufferList->Status); } FwpsFreeCloneNetBufferList(pNetBufferList, 0); TRACE_EXIT(); return; }
static NTSTATUS InitWskData( OUT PIRP* pIrp, OUT PKEVENT CompletionEvent ) { ASSERT(pIrp); ASSERT(CompletionEvent); TRACE_ENTER(); *pIrp = IoAllocateIrp(1, FALSE); if (!*pIrp) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "InitWskData()::IoAllocateIrp() failed with status 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES); return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeEvent(CompletionEvent, SynchronizationEvent, FALSE); IoSetCompletionRoutine(*pIrp, CompletionRoutine, CompletionEvent, TRUE, TRUE, TRUE); TRACE_EXIT(); return STATUS_SUCCESS; }
//------------------------------------------------------------------- NTSTATUS NPF_Cleanup(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) { POPEN_INSTANCE Open; NDIS_STATUS Status; PIO_STACK_LOCATION IrpSp; LARGE_INTEGER ThreadDelay; ULONG localNumOpenInstances; TRACE_ENTER(); IrpSp = IoGetCurrentIrpStackLocation(Irp); Open = IrpSp->FileObject->FsContext; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open = %p\n", Open); ASSERT(Open != NULL); NPF_CloseOpenInstance(Open); if (Open->ReadEvent != NULL) KeSetEvent(Open->ReadEvent,0,FALSE); NPF_CloseBinding(Open); // NOTE: // code commented out because the kernel dump feature is disabled // //if (AdapterAlreadyClosing == FALSE) //{ // // Unfreeze the consumer // // if(Open->mode & MODE_DUMP) // NdisSetEvent(&Open->DumpEvent); // else // KeSetEvent(Open->ReadEvent,0,FALSE); // // // // If this instance is in dump mode, complete the dump and close the file // // // if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL) // { // NTSTATUS wres; // ThreadDelay.QuadPart = -50000000; // // // // Wait the completion of the thread // // // wres = KeWaitForSingleObject(Open->DumpThreadObject, // UserRequest, // KernelMode, // TRUE, // &ThreadDelay); // ObDereferenceObject(Open->DumpThreadObject); // // // // Flush and close the dump file // // // NPF_CloseDumpFile(Open); // } //} // // release all the resources // NPF_ReleaseOpenInstanceResources(Open); // IrpSp->FileObject->FsContext = NULL; // // Decrease the counter of open instances // localNumOpenInstances = InterlockedDecrement(&g_NumOpenedInstances); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenInstances); if(localNumOpenInstances == 0) { // // Force a synchronization at the next NPF_Open(). // This hopefully avoids the synchronization issues caused by hibernation or standby. // TIME_DESYNCHRONIZE(&G_Start_Time); } // // and complete the IRP with status success // Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); TRACE_EXIT(); return(STATUS_SUCCESS); }
VOID NPF_ReleaseOpenInstanceResources(POPEN_INSTANCE pOpen) { PKEVENT pEvent; UINT i; TRACE_ENTER(); ASSERT(pOpen != NULL); ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open= %p", pOpen); NdisFreePacketPool(pOpen->PacketPool); #ifdef HAVE_BUGGY_TME_SUPPORT // // free mem_ex // pOpen->mem_ex.size = 0; if(pOpen->mem_ex.buffer != NULL) ExFreePool(pOpen->mem_ex.buffer); #endif //HAVE_BUGGY_TME_SUPPORT // // Free the filter if it's present // if(pOpen->bpfprogram != NULL) ExFreePool(pOpen->bpfprogram); // // Jitted filters are supported on x86 (32bit) only // #ifdef _X86_ // Free the jitted filter if it's present if(pOpen->Filter != NULL) BPF_Destroy_JIT_Filter(pOpen->Filter); #endif //_X86_ // // Dereference the read event. // if (pOpen->ReadEvent != NULL) ObDereferenceObject(pOpen->ReadEvent); // // free the buffer // NOTE: the buffer is fragmented among the various CPUs, but the base pointer of the // allocated chunk of memory is stored in the first slot (pOpen->CpuData[0]) // if (pOpen->Size > 0) ExFreePool(pOpen->CpuData[0].Buffer); // // free the per CPU spinlocks // for (i = 0; i < g_NCpu; i++) { NdisFreeSpinLock(&Open->CpuData[i].BufferLock); } // // Free the string with the name of the dump file // if(pOpen->DumpFileName.Buffer!=NULL) ExFreePool(pOpen->DumpFileName.Buffer); TRACE_EXIT(); }
NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PDEVICE_EXTENSION DeviceExtension; POPEN_INSTANCE Open; PIO_STACK_LOCATION IrpSp; NDIS_STATUS Status; NDIS_STATUS ErrorStatus; UINT i; PUCHAR tpointer; PLIST_ENTRY PacketListEntry; NTSTATUS returnStatus; // // Old registry based WinPcap names // // WCHAR EventPrefix[MAX_WINPCAP_KEY_CHARS]; // UINT RegStrLen; TRACE_ENTER(); DeviceExtension = DeviceObject->DeviceExtension; IrpSp = IoGetCurrentIrpStackLocation(Irp); // allocate some memory for the open structure Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA'); if (Open==NULL) { // no memory Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory( Open, sizeof(OPEN_INSTANCE) ); // // Old registry based WinPcap names // // // // // Get the Event names base from the registry // // // RegStrLen = sizeof(EventPrefix)/sizeof(EventPrefix[0]); // // NPF_QueryWinpcapRegistryString(NPF_EVENTS_NAMES_REG_KEY_WC, // EventPrefix, // RegStrLen, // NPF_EVENTS_NAMES_WIDECHAR); // Open->DeviceExtension=DeviceExtension; // Allocate a packet pool for our xmit and receive packets NdisAllocatePacketPool( &Status, &Open->PacketPool, TRANSMIT_PACKETS, sizeof(PACKET_RESERVED)); if (Status != NDIS_STATUS_SUCCESS) { TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool"); ExFreePool(Open); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } NdisInitializeEvent(&Open->WriteEvent); NdisInitializeEvent(&Open->NdisRequestEvent); NdisInitializeEvent(&Open->NdisWriteCompleteEvent); NdisInitializeEvent(&Open->DumpEvent); NdisAllocateSpinLock(&Open->MachineLock); NdisAllocateSpinLock(&Open->WriteLock); Open->WriteInProgress = FALSE; for (i = 0; i < g_NCpu; i++) { NdisAllocateSpinLock(&Open->CpuData[i].BufferLock); } NdisInitializeEvent(&Open->NdisOpenCloseCompleteEvent); // list to hold irp's want to reset the adapter InitializeListHead(&Open->ResetIrpList); // Initialize the request list KeInitializeSpinLock(&Open->RequestSpinLock); InitializeListHead(&Open->RequestList); #ifdef HAVE_BUGGY_TME_SUPPORT // Initializes the extended memory of the NPF machine Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, '2OWA'); if((Open->mem_ex.buffer) == NULL) { // // no memory // ExFreePool(Open); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } Open->mem_ex.size = DEFAULT_MEM_EX_SIZE; RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE); #endif //HAVE_BUGGY_TME_SUPPORT // // Initialize the open instance // Open->bpfprogram = NULL; //reset the filter Open->mode = MODE_CAPT; Open->Nbytes.QuadPart = 0; Open->Npackets.QuadPart = 0; Open->Nwrites = 1; Open->Multiple_Write_Counter = 0; Open->MinToCopy = 0; Open->TimeOut.QuadPart = (LONGLONG)1; Open->DumpFileName.Buffer = NULL; Open->DumpFileHandle = NULL; #ifdef HAVE_BUGGY_TME_SUPPORT Open->tme.active = TME_NONE_ACTIVE; #endif // HAVE_BUGGY_TME_SUPPORT Open->DumpLimitReached = FALSE; Open->MaxFrameSize = 0; Open->WriterSN=0; Open->ReaderSN=0; Open->Size=0; Open->SkipSentPackets = FALSE; Open->ReadEvent = NULL; // // we need to keep a counter of the pending IRPs // so that when the IRP_MJ_CLEANUP dispatcher gets called, // we can wait for those IRPs to be completed // Open->NumPendingIrps = 0; Open->ClosePending = FALSE; NdisAllocateSpinLock(&Open->OpenInUseLock); // //allocate the spinlock for the statistic counters // NdisAllocateSpinLock(&Open->CountersLock); // // link up the request stored in our open block // for (i = 0 ; i < MAX_REQUESTS ; i++ ) { NdisInitializeEvent(&Open->Requests[i].InternalRequestCompletedEvent); ExInterlockedInsertTailList( &Open->RequestList, &Open->Requests[i].ListElement, &Open->RequestSpinLock); } NdisResetEvent(&Open->NdisOpenCloseCompleteEvent); // // set the proper binding flags before trying to open the MAC // Open->AdapterBindingStatus = ADAPTER_BOUND; Open->AdapterHandleUsageCounter = 0; NdisAllocateSpinLock(&Open->AdapterHandleLock); // // Try to open the MAC // TRACE_MESSAGE2(PACKET_DEBUG_LOUD,"Opening the device %ws, BindingContext=%p",DeviceExtension->AdapterName.Buffer, Open); returnStatus = STATUS_SUCCESS; NdisOpenAdapter( &Status, &ErrorStatus, &Open->AdapterHandle, &Open->Medium, MediumArray, NUM_NDIS_MEDIA, g_NdisProtocolHandle, Open, &DeviceExtension->AdapterName, 0, NULL); TRACE_MESSAGE1(PACKET_DEBUG_LOUD,"Opened the device, Status=%x",Status); if (Status == NDIS_STATUS_PENDING) { NdisWaitEvent(&Open->NdisOpenCloseCompleteEvent, 0); if (!NT_SUCCESS(Open->OpenCloseStatus)) { returnStatus = Open->OpenCloseStatus; } else { returnStatus = STATUS_SUCCESS; } } else { // // request not pending, we know the result, and OpenComplete has not been called. // if (Status == NDIS_STATUS_SUCCESS) { returnStatus = STATUS_SUCCESS; } else { // // this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS // returnStatus = Status; } } if (returnStatus == STATUS_SUCCESS) { ULONG localNumOpenedInstances; // // complete the open // localNumOpenedInstances = InterlockedIncrement(&g_NumOpenedInstances); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenedInstances); // Get the absolute value of the system boot time. // This is used for timestamp conversion. TIME_SYNCHRONIZE(&G_Start_Time); returnStatus = NPF_GetDeviceMTU(Open, Irp, &Open->MaxFrameSize); if (!NT_SUCCESS(returnStatus)) { // // Close the binding // NPF_CloseBinding(Open); } } if (!NT_SUCCESS(returnStatus)) { NPF_ReleaseOpenInstanceResources(Open); // // Free the open instance itself // ExFreePool(Open); } else { // Save or open here IrpSp->FileObject->FsContext=Open; } Irp->IoStatus.Status = returnStatus; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); TRACE_EXIT(); return returnStatus; }
LONG NTAPI WSKSendTo_NBL( IN PWSK_SOCKET WskSocket, IN PNET_BUFFER_LIST NetBufferList, IN ULONG BufferOffset, __in_opt PSOCKADDR RemoteAddress ) { KEVENT CompletionEvent = { 0 }; PIRP Irp = NULL; WSK_BUF WskBuffer = { 0 }; LONG BytesSent = SOCKET_ERROR; NTSTATUS Status = STATUS_UNSUCCESSFUL; TRACE_ENTER(); if (g_SocketsState != INITIALIZED || !WskSocket || !NetBufferList) { TRACE_EXIT(); return SOCKET_ERROR; } Status = InitWskBuffer_NBL(NetBufferList, BufferOffset, &WskBuffer); if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo_NBL()::InitWskBuffer_NBL() failed with status 0x%08X\n", Status); TRACE_EXIT(); return SOCKET_ERROR; } Status = InitWskData(&Irp, &CompletionEvent); if (!NT_SUCCESS(Status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "WSKSendTo_NBL()::InitWskData() failed with status 0x%08X\n", Status); FreeWskBuffer_NBL(&WskBuffer); TRACE_EXIT(); return SOCKET_ERROR; } Status = ((PWSK_PROVIDER_DATAGRAM_DISPATCH)WskSocket->Dispatch)->WskSendTo( WskSocket, &WskBuffer, 0, RemoteAddress, 0, NULL, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); Status = Irp->IoStatus.Status; } BytesSent = NT_SUCCESS(Status) ? (LONG)Irp->IoStatus.Information : SOCKET_ERROR; IoFreeIrp(Irp); FreeWskBuffer_NBL(&WskBuffer); TRACE_EXIT(); return BytesSent; }
NTSTATUS NTAPI NPF_WSKSendPacket_NBL( IN PNET_BUFFER_LIST NetBufferList ) { PMDL pMdl = NULL; ULONG BuffSize; PETHER_HEADER pEthernetHdr; PDLT_NULL_HEADER pDltNullHdr; NTSTATUS status = STATUS_UNSUCCESSFUL; TRACE_ENTER(); pMdl = NetBufferList->FirstNetBuffer->CurrentMdl; if (pMdl) { NdisQueryMdl( pMdl, &pEthernetHdr, &BuffSize, NormalPagePriority); pDltNullHdr = (PDLT_NULL_HEADER) pEthernetHdr; } else { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL()::NetBufferList->FirstNetBuffer->CurrentMdl failed with pMdl 0x%p\n", pMdl); TRACE_EXIT(); return status; } if (pEthernetHdr == NULL) { // // The system is low on resources. Set up to handle failure // below. // TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL()::NdisQueryMdl() failed with pEthernetHdr 0x%p\n", pEthernetHdr); TRACE_EXIT(); return status; } if (g_DltNullMode) { if (pDltNullHdr->null_type == DLTNULLTYPE_IP) { status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV4, NetBufferList, DLT_NULL_HDR_LEN); } else if (pDltNullHdr->null_type == DLTNULLTYPE_IPV6) { status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV6, NetBufferList, DLT_NULL_HDR_LEN); } else { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL() failed with status 0x%08X, not valid loopback IPv4 or IPv6 packet (DLT_NULL)\n", status); } } else { if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IP)) { status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV4, NetBufferList, ETHER_HDR_LEN); } else if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IPV6)) { status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV6, NetBufferList, ETHER_HDR_LEN); } else { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL() failed with status 0x%08X, not valid loopback IPv4 or IPv6 packet\n", status); } } TRACE_EXIT(); return status; }
NTSTATUS NTAPI NPF_WSKInitSockets( ) { NTSTATUS status = STATUS_SUCCESS; TRACE_ENTER(); // IPv4 Socket Initialization g_IPv4Socket = WSKCreateSocket(AF_INET, SOCK_RAW, IPPROTO_NPCAP_LOOPBACK, WSK_FLAG_DATAGRAM_SOCKET); if (g_IPv4Socket == NULL) { status = STATUS_UNSUCCESSFUL; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKCreateSocket() failed with status 0x%08X\n", status); TRACE_EXIT(); return status; } g_IPv4LocalAddress.sin_family = AF_INET; g_IPv4LocalAddress.sin_addr.s_addr = INADDR_ANY; // g_IPv4LocalAddress.sin_port = INADDR_PORT; // Bind Required status = WSKBind(g_IPv4Socket, (PSOCKADDR) &g_IPv4LocalAddress); if (!NT_SUCCESS(status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKBind() failed with status 0x%08X\n", status); WSKCloseSocket(g_IPv4Socket); g_IPv4Socket = NULL; TRACE_EXIT(); return status; } g_IPv4RemoteAddress.sin_family = AF_INET; g_IPv4RemoteAddress.sin_addr.s_addr = HTON_LONG(INADDR_LOOPBACK); // g_IPv4RemoteAddress.sin_port = HTON_SHORT(LOG_PORT); //////////////////////////////////////////////////////////////////////////////////////////////////////////// // IPv6 Socket Initialization g_IPv6Socket = WSKCreateSocket(AF_INET6, SOCK_RAW, IPPROTO_NPCAP_LOOPBACK, WSK_FLAG_DATAGRAM_SOCKET); if (g_IPv6Socket == NULL) { status = STATUS_UNSUCCESSFUL; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKCreateSocket() failed with status 0x%08X\n", status); TRACE_EXIT(); return status; } g_IPv6LocalAddress.sin6_family = AF_INET6; struct in6_addr in6AnyAddr = IN6ADDR_ANY_INIT; g_IPv6LocalAddress.sin6_addr = in6AnyAddr; // g_IPv6LocalAddress.sin_port = INADDR_PORT; // Bind Required status = WSKBind(g_IPv6Socket, (PSOCKADDR) &g_IPv6LocalAddress); if (!NT_SUCCESS(status)) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKInitSockets()::WSKBind() failed with status 0x%08X\n", status); WSKCloseSocket(g_IPv6Socket); g_IPv6Socket = NULL; TRACE_EXIT(); return status; } g_IPv6RemoteAddress.sin6_family = AF_INET6; struct in6_addr in6LoopbackAddr = IN6ADDR_LOOPBACK_INIT; g_IPv6RemoteAddress.sin6_addr = in6LoopbackAddr; // g_IPv6RemoteAddress.sin_port = HTON_SHORT(LOG_PORT); TRACE_EXIT(); return status; }
void NPF_NetworkClassify( _In_ const FWPS_INCOMING_VALUES* inFixedValues, _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, _Inout_opt_ void* layerData, _In_ const FWPS_FILTER* filter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT* classifyOut ) #endif { POPEN_INSTANCE GroupOpen; POPEN_INSTANCE TempOpen; NTSTATUS status = STATUS_SUCCESS; UINT32 ipHeaderSize = 0; UINT32 bytesRetreated = 0; UINT32 bytesRetreatedEthernet = 0; INT32 iIPv4 = -1; INT32 iDrection = -1; BOOLEAN bSelfSent = FALSE; PVOID pContiguousData = NULL; NET_BUFFER* pNetBuffer = 0; UCHAR pPacketData[ETHER_HDR_LEN]; PNET_BUFFER_LIST pNetBufferList = (NET_BUFFER_LIST*) layerData; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; FWPS_PACKET_INJECTION_STATE injectionState = FWPS_PACKET_INJECTION_STATE_MAX; #if(NTDDI_VERSION >= NTDDI_WIN7) UNREFERENCED_PARAMETER(classifyContext); #endif UNREFERENCED_PARAMETER(filter); UNREFERENCED_PARAMETER(flowContext); // Make the default action. if (classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) classifyOut->actionType = FWP_ACTION_CONTINUE; #if(NTDDI_VERSION >= NTDDI_WIN7) // Filter out fragment packets and reassembled packets. if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FRAGMENT_DATA) { return; } if (inMetaValues->currentMetadataValues & FWP_CONDITION_FLAG_IS_REASSEMBLED) { return; } #endif TRACE_ENTER(); // Get the packet protocol (IPv4 or IPv6) and the direction (Inbound or Outbound). if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4) { iIPv4 = 1; } else // if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) { iIPv4 = 0; } if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) { iDrection = 0; } else // if (inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) { iDrection = 1; } if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_IP_HEADER_SIZE) { ipHeaderSize = inMetaValues->ipHeaderSize; } injectionState = FwpsQueryPacketInjectionState(iIPv4 ? g_InjectionHandle_IPv4 : g_InjectionHandle_IPv6, pNetBufferList, NULL); if (injectionState == FWPS_PACKET_INJECTED_BY_SELF || injectionState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) { TRACE_MESSAGE(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: this packet is injected by ourself, let it go\n"); TRACE_EXIT(); return; } // Inbound: Initial offset is at the Transport Header, so retreat the size of the Ethernet Header and IP Header. // Outbound: Initial offset is at the IP Header, so just retreat the size of the Ethernet Header. // We retreated the packet in two phases: 1) retreat the IP Header (if has), 2) clone the packet and retreat the Ethernet Header. // We must NOT retreat the Ethernet Header on the original packet, or this will lead to BAD_POOL_CALLER Bluescreen. bytesRetreated = iDrection ? ipHeaderSize : 0; status = NdisRetreatNetBufferListDataStart(pNetBufferList, bytesRetreated, 0, NULL, NULL); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(bytesRetreated) [status: %#x]\n", status); TRACE_EXIT(); return; } //bSelfSent = NPF_IsPacketSelfSent(pNetBufferList, (BOOLEAN)iIPv4); bSelfSent = (iDrection == 0) ? FALSE : NPF_IsPacketSelfSent(pNetBufferList, (BOOLEAN) iIPv4); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: %#x]\n", bSelfSent); if (bSelfSent) { NdisAdvanceNetBufferListDataStart(pNetBufferList, iIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN, FALSE, 0); } // Here if this NBL is sent by ourself, we will clone it starting from IP header and inject it into Network Layer send path. if (bSelfSent) { PNET_BUFFER_LIST pClonedNetBufferList_Injection; status = FwpsAllocateCloneNetBufferList(pNetBufferList, NULL, NULL, 0, &pClonedNetBufferList_Injection); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: FwpsAllocateCloneNetBufferList(pClonedNetBufferList_Injection) [status: %#x]\n", status); goto Exit_WSK_IP_Retreated; } if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)inMetaValues->compartmentId; // This cloned NBL will be freed in NPF_NetworkInjectionComplete function. status = FwpsInjectNetworkSendAsync(iIPv4 ? g_InjectionHandle_IPv4 : g_InjectionHandle_IPv6, NULL, 0, compartmentID, pClonedNetBufferList_Injection, NPF_NetworkInjectionComplete, NULL); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: FwpsInjectNetworkSendAsync() [status: %#x]\n", status); FwpsFreeCloneNetBufferList(pClonedNetBufferList_Injection, 0); goto Exit_WSK_IP_Retreated; } // We have successfully re-inject the cloned NBL, so remove this one. classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; classifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; } // We clone this NBL again, for packet reading operation. PNET_BUFFER_LIST pClonedNetBufferList; status = FwpsAllocateCloneNetBufferList(pNetBufferList, NULL, NULL, 0, &pClonedNetBufferList); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); goto Exit_WSK_IP_Retreated; } bytesRetreatedEthernet = g_DltNullMode ? DLT_NULL_HDR_LEN : ETHER_HDR_LEN; status = NdisRetreatNetBufferListDataStart(pClonedNetBufferList, bytesRetreatedEthernet, 0, 0, 0); if (status != STATUS_SUCCESS) { bytesRetreatedEthernet = 0; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(bytesRetreatedEthernet) [status: %#x]\n", status); goto Exit_Packet_Cloned; } pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pClonedNetBufferList); while (pNetBuffer) { pContiguousData = NdisGetDataBuffer(pNetBuffer, bytesRetreatedEthernet, pPacketData, 1, 0); if (!pContiguousData) { status = STATUS_UNSUCCESSFUL; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NdisGetDataBuffer() [status: %#x]\n", status); goto Exit_Ethernet_Retreated; } else { if (g_DltNullMode) { ((PDLT_NULL_HEADER) pContiguousData)->null_type = iIPv4 ? DLTNULLTYPE_IP : DLTNULLTYPE_IPV6; } else { RtlZeroMemory(pContiguousData, ETHER_ADDR_LEN * 2); ((PETHER_HEADER) pContiguousData)->ether_type = iIPv4 ? RtlUshortByteSwap(ETHERTYPE_IP) : RtlUshortByteSwap(ETHERTYPE_IPV6); } } pNetBuffer = pNetBuffer->Next; } // Send the loopback packets data to the user-mode code. if (g_LoopbackOpenGroupHead) { //get the 1st group adapter child GroupOpen = g_LoopbackOpenGroupHead->GroupNext; } else { // Should not come here GroupOpen = NULL; } while (GroupOpen != NULL) { TempOpen = GroupOpen; if (TempOpen->AdapterBindingStatus == ADAPTER_BOUND) { //let every group adapter receive the packets NPF_TapExForEachOpen(TempOpen, pClonedNetBufferList); } GroupOpen = TempOpen->GroupNext; } Exit_Ethernet_Retreated: // Advance the offset back to the original position. NdisAdvanceNetBufferListDataStart(pClonedNetBufferList, bytesRetreatedEthernet, FALSE, 0); Exit_Packet_Cloned: FwpsFreeCloneNetBufferList(pClonedNetBufferList, 0); Exit_WSK_IP_Retreated: if (bSelfSent) { status = NdisRetreatNetBufferListDataStart(pNetBufferList, iIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN, 0, NULL, NULL); // if (status != STATUS_SUCCESS) // { // TRACE_MESSAGE1(PACKET_DEBUG_LOUD, // "NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(IP_HDR_LEN) [status: %#x]\n", // status); // // goto Exit_IP_Retreated; // } } /*Exit_IP_Retreated:*/ NdisAdvanceNetBufferListDataStart(pNetBufferList, bytesRetreated, FALSE, 0); // // print "protocol, direction, fragment, reassembled" info for the current packet. // // int iFragment = -1; // if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FRAGMENT_DATA) // { // iFragment = 1; // } // else // { // iFragment = 0; // } // // int iReassembled = -1; // if (inMetaValues->currentMetadataValues & FWP_CONDITION_FLAG_IS_REASSEMBLED) // { // iReassembled = 1; // } // else // { // iReassembled = 0; // } // IF_LOUD(DbgPrint("\n\nNPF_NetworkClassify: Loopback packet found !!! protocol=[%d] (ipv4=0, ipv6=1), direction=[%d] (out=0, in=1), fragment=[%d], reassembled=[%d]\n", iProtocol, iDrection, iFragment, iReassembled);) TRACE_EXIT(); return; }