From 749497dde0a1dd08c434a73b9d4e93dc3e3326d9 Mon Sep 17 00:00:00 2001 From: dnobori Date: Sat, 4 Jan 2014 22:00:08 +0900 Subject: v4.03-9408-rtm --- src/See/dump.c | 570 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 src/See/dump.c (limited to 'src/See/dump.c') diff --git a/src/See/dump.c b/src/See/dump.c new file mode 100644 index 00000000..e60aa6cb --- /dev/null +++ b/src/See/dump.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 1999 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include +#include +#include "debug.h" +#include "packet.h" + +#include "win_bpf.h" + +//------------------------------------------------------------------- + +NTSTATUS +NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append) +{ + NTSTATUS ntStatus; + IO_STATUS_BLOCK IoStatus; + OBJECT_ATTRIBUTES ObjectAttributes; + PWCHAR PathPrefix; + USHORT PathLen; + UNICODE_STRING FullFileName; + ULONG FullFileNameLength; + PDEVICE_OBJECT fsdDevice; + + IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");) + + if(fileName->Buffer[0] == L'\\' && + fileName->Buffer[1] == L'?' && + fileName->Buffer[2] == L'?' && + fileName->Buffer[3] == L'\\' + ){ + PathLen = 0; + } + else{ + PathPrefix = L"\\??\\"; + PathLen = 8; + } + + // Insert the correct path prefix. + FullFileNameLength = PathLen + fileName->MaximumLength; + + FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool, + FullFileNameLength, + '0DWA'); + + if (FullFileName.Buffer == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + return ntStatus; + } + + FullFileName.Length = PathLen; + FullFileName.MaximumLength = (USHORT)FullFileNameLength; + + if(PathLen) + RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen); + + RtlAppendUnicodeStringToString (&FullFileName, fileName); + + IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);) + + InitializeObjectAttributes ( &ObjectAttributes, + &FullFileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + // Create the dump file + ntStatus = ZwCreateFile( &Open->DumpFileHandle, + SYNCHRONIZE | FILE_WRITE_DATA, + &ObjectAttributes, + &IoStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + (Append)?FILE_OPEN_IF:FILE_SUPERSEDE, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 ); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);) + + ExFreePool(FullFileName.Buffer); + Open->DumpFileHandle=NULL; + ntStatus = STATUS_NO_SUCH_FILE; + return ntStatus; + } + + ExFreePool(FullFileName.Buffer); + + ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle, + FILE_WRITE_ACCESS, + *IoFileObjectType, + KernelMode, + &Open->DumpFileObject, + 0); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);) + + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + ntStatus = STATUS_NO_SUCH_FILE; + return ntStatus; + } + + fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject); + + IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);) + + return ntStatus; +} + +//------------------------------------------------------------------- + +NTSTATUS +NPF_StartDump(POPEN_INSTANCE Open) +{ + NTSTATUS ntStatus; + struct packet_file_header hdr; + IO_STATUS_BLOCK IoStatus; + + IF_LOUD(DbgPrint("NPF: StartDump.\n");) + + // Init the file header + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + hdr.thiszone = 0; /*Currently not set*/ + hdr.snaplen = 1514; + hdr.sigfigs = 0; + + // Detect the medium type + switch (Open->Medium){ + + case NdisMediumWan: + hdr.linktype = DLT_EN10MB; + break; + + case NdisMedium802_3: + hdr.linktype = DLT_EN10MB; + break; + + case NdisMediumFddi: + hdr.linktype = DLT_FDDI; + break; + + case NdisMedium802_5: + hdr.linktype = DLT_IEEE802; + break; + + case NdisMediumArcnet878_2: + hdr.linktype = DLT_ARCNET; + break; + + case NdisMediumAtm: + hdr.linktype = DLT_ATM_RFC1483; + break; + + default: + hdr.linktype = DLT_EN10MB; + } + + // Write the header. + // We can use ZwWriteFile because we are in the context of the application + ntStatus = ZwWriteFile(Open->DumpFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + &hdr, + sizeof(hdr), + NULL, + NULL ); + + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);) + + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + ntStatus = STATUS_NO_SUCH_FILE; + return ntStatus; + } + + Open->DumpOffset.QuadPart=24; + + ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle, + THREAD_ALL_ACCESS, + (ACCESS_MASK)0L, + 0, + 0, + NPF_DumpThread, + Open); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);) + + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + return ntStatus; + } + + ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &Open->DumpThreadObject, + 0); + + if ( !NT_SUCCESS( ntStatus ) ) + { + IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);) + + ObDereferenceObject(Open->DumpFileObject); + ZwClose( Open->DumpFileHandle ); + Open->DumpFileHandle=NULL; + + return ntStatus; + } + + + return ntStatus; + +} + +//------------------------------------------------------------------- +// Dump Thread +//------------------------------------------------------------------- + +VOID NPF_DumpThread(POPEN_INSTANCE Open) +{ +// ULONG FrozenNic; + + IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open);) + + while(TRUE){ + + // Wait until some packets arrive or the timeout expires + NdisWaitEvent(&Open->DumpEvent, 5000); + + IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");) + + if(Open->DumpLimitReached || + Open->Size==0){ // BufSize=0 means that this instance was closed, or that the buffer is too + // small for any capture. In both cases it is better to end the dump + + IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");) + IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);) + + PsTerminateSystemThread(STATUS_SUCCESS); + return; + } + + NdisResetEvent(&Open->DumpEvent); + + // Write the content of the buffer to the file + if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){ + PsTerminateSystemThread(STATUS_SUCCESS); + return; + } + + } + +} + +//------------------------------------------------------------------- + +NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open) +{ +#if 0 + + Thead=Open->Bhead; + Ttail=Open->Btail; + TLastByte=Open->BLastByte; + + IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");) + + // Get the address of the buffer + CurrBuff=Open->Buffer; + // + // Fill the application buffer + // + if( Ttail < Thead ) + { + if(Open->MaxDumpBytes && + (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes) + { + // Size limit reached + UINT PktLen; + + SizeToDump = 0; + + // Scan the buffer to detect the exact amount of data to save + while(TRUE){ + PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); + + if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) + break; + + SizeToDump += PktLen; + } + + } + else + SizeToDump = TLastByte-Thead; + + lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); + if (lMdl == NULL) + { + // No memory: stop dump + IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) + return STATUS_UNSUCCESSFUL; + } + + MmBuildMdlForNonPagedPool(lMdl); + + // Write to disk + NPF_WriteDumpFile(Open->DumpFileObject, + &Open->DumpOffset, + SizeToDump, + lMdl, + &IoStatus); + + IoFreeMdl(lMdl); + + if(!NT_SUCCESS(IoStatus.Status)){ + // Error + return STATUS_UNSUCCESSFUL; + } + + if(SizeToDump != TLastByte-Thead){ + // Size limit reached. + Open->DumpLimitReached = TRUE; + + // Awake the application + KeSetEvent(Open->ReadEvent,0,FALSE); + + return STATUS_UNSUCCESSFUL; + } + + // Update the packet buffer + Open->DumpOffset.QuadPart+=(TLastByte-Thead); + Open->BLastByte=Ttail; + Open->Bhead=0; + } + + if( Ttail > Thead ){ + + if(Open->MaxDumpBytes && + (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes) + { + // Size limit reached + UINT PktLen; + + SizeToDump = 0; + + // Scan the buffer to detect the exact amount of data to save + while(Thead + SizeToDump < Ttail){ + + PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); + + if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) + break; + + SizeToDump += PktLen; + } + + } + else + SizeToDump = Ttail-Thead; + + lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); + if (lMdl == NULL) + { + // No memory: stop dump + IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) + return STATUS_UNSUCCESSFUL; + } + + MmBuildMdlForNonPagedPool(lMdl); + + // Write to disk + NPF_WriteDumpFile(Open->DumpFileObject, + &Open->DumpOffset, + SizeToDump, + lMdl, + &IoStatus); + + IoFreeMdl(lMdl); + + if(!NT_SUCCESS(IoStatus.Status)){ + // Error + return STATUS_UNSUCCESSFUL; + } + + if(SizeToDump != Ttail-Thead){ + // Size limit reached. + Open->DumpLimitReached = TRUE; + + // Awake the application + KeSetEvent(Open->ReadEvent,0,FALSE); + + return STATUS_UNSUCCESSFUL; + } + + // Update the packet buffer + Open->DumpOffset.QuadPart+=(Ttail-Thead); + Open->Bhead=Ttail; + + } +#endif + return STATUS_SUCCESS; +} + +//------------------------------------------------------------------- + +NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){ +#if 0 + IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");) + IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);) + +DbgPrint("1\n"); + // Consistency check + if(Open->DumpFileHandle == NULL) + return STATUS_UNSUCCESSFUL; + +DbgPrint("2\n"); + ZwClose( Open->DumpFileHandle ); + + ObDereferenceObject(Open->DumpFileObject); +/* + if(Open->DumpLimitReached == TRUE) + // Limit already reached: don't save the rest of the buffer. + return STATUS_SUCCESS; +*/ +DbgPrint("3\n"); + + NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE); + + // Flush the buffer to file + NPF_SaveCurrentBuffer(Open); + + // Close The file + ObDereferenceObject(Open->DumpFileObject); + ZwClose( Open->DumpFileHandle ); + + Open->DumpFileHandle = NULL; + + ObDereferenceObject(Open->DumpFileObject); +#endif + return STATUS_SUCCESS; +} + +//------------------------------------------------------------------- + +static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Context) +{ + + // Copy the status information back into the "user" IOSB + *Irp->UserIosb = Irp->IoStatus; + + // Wake up the mainline code + KeSetEvent(Irp->UserEvent, 0, FALSE); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +//------------------------------------------------------------------- + +VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject, + PLARGE_INTEGER Offset, + ULONG Length, + PMDL Mdl, + PIO_STATUS_BLOCK IoStatusBlock) +{ + PIRP irp; + KEVENT event; + PIO_STACK_LOCATION ioStackLocation; + PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject); + + // Set up the event we'll use + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + // Allocate and build the IRP we'll be sending to the FSD + irp = IoAllocateIrp(fsdDevice->StackSize, FALSE); + + if (!irp) { + // Allocation failed, presumably due to memory allocation failure + IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; + IoStatusBlock->Information = 0; + + return; + } + + irp->MdlAddress = Mdl; + irp->UserEvent = &event; + irp->UserIosb = IoStatusBlock; + irp->Tail.Overlay.Thread = PsGetCurrentThread(); + irp->Tail.Overlay.OriginalFileObject= FileObject; + irp->RequestorMode = KernelMode; + + // Indicate that this is a WRITE operation + irp->Flags = IRP_WRITE_OPERATION; + + // Set up the next I/O stack location + ioStackLocation = IoGetNextIrpStackLocation(irp); + ioStackLocation->MajorFunction = IRP_MJ_WRITE; + ioStackLocation->MinorFunction = 0; + ioStackLocation->DeviceObject = fsdDevice; + ioStackLocation->FileObject = FileObject; + IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE); + ioStackLocation->Parameters.Write.Length = Length; + ioStackLocation->Parameters.Write.ByteOffset = *Offset; + + + // Send it on. Ignore the return code + (void) IoCallDriver(fsdDevice, irp); + + // Wait for the I/O to complete. + KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); + + // Free the IRP now that we are done with it + IoFreeIrp(irp); + + return; + +} -- cgit v1.2.3