Main Page Modules Data Structures File List Data Fields Globals Related Pages

# dump.c

Go to the documentation of this file.

    00001 /*
    00002  * Copyright (c) 1999 - 2003
    00003  * NetGroup, Politecnico di Torino (Italy)
    00004  * All rights reserved.
    00005  *
    00006  * Redistribution and use in source and binary forms, with or without
    00007  * modification, are permitted provided that the following conditions
    00008  * are met:
    00009  *
    00010  * 1. Redistributions of source code must retain the above copyright
    00011  * notice, this list of conditions and the following disclaimer.
    00012  * 2. Redistributions in binary form must reproduce the above copyright
    00013  * notice, this list of conditions and the following disclaimer in the
    00014  * documentation and/or other materials provided with the distribution.
    00015  * 3. Neither the name of the Politecnico di Torino nor the names of its
    00016  * contributors may be used to endorse or promote products derived from
    00017  * this software without specific prior written permission.
    00018  *
    00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    00020  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    00022  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    00023  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    00024  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    00025  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    00026  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    00027  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    00029  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00030  *
    00031  */
    00032
    00033 #include <stdarg.h>
    00034 #include <ntddk.h>
    00035 #include <ntiologc.h>
    00036 #include <ndis.h>
    00037 #include "debug.h"
    00038 #include "packet.h"
    00039
    00040 #include "win_bpf.h"
    00041
    00042 //-------------------------------------------------------------------
    00043
    00044 NTSTATUS
    00045 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
    00046 {
    00047    NTSTATUS ntStatus;
    00048    IO_STATUS_BLOCK IoStatus;
    00049    OBJECT_ATTRIBUTES ObjectAttributes;
    00050    PWCHAR PathPrefix;
    00051    USHORT PathLen;
    00052    UNICODE_STRING FullFileName;
    00053    ULONG FullFileNameLength;
    00054    PDEVICE_OBJECT fsdDevice;
    00055
    00056    FILE_STANDARD_INFORMATION StandardInfo;
    00057
    00058     IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
    00059
    00060    if(fileName->Buffer[0] == L'\\' &&
    00061       fileName->Buffer[1] == L'?' &&
    00062       fileName->Buffer[2] == L'?' &&
    00063       fileName->Buffer[3] == L'\\'
    00064    ){
    00065       PathLen = 0;
    00066    }
    00067    else{
    00068       PathPrefix = L"\\??\\";
    00069       PathLen = 8;
    00070    }
    00071
    00072    // Insert the correct path prefix.
    00073    FullFileNameLength = PathLen + fileName->MaximumLength;
    00074
    00075    FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
    00076       FullFileNameLength,
    00077       '0DWA');
    00078
    00079    if (FullFileName.Buffer == NULL) {
    00080       ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    00081       return ntStatus;
    00082    }
    00083
    00084    FullFileName.Length = PathLen;
    00085    FullFileName.MaximumLength = (USHORT)FullFileNameLength;
    00086
    00087    if(PathLen)
    00088       RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
    00089
    00090    RtlAppendUnicodeStringToString (&FullFileName, fileName);
    00091
    00092    IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
    00093
    00094    InitializeObjectAttributes ( &ObjectAttributes,
    00095       &FullFileName,
    00096       OBJ_CASE_INSENSITIVE,
    00097       NULL,
    00098       NULL );
    00099
    00100    // Create the dump file
    00101    ntStatus = ZwCreateFile( &Open->DumpFileHandle,
    00102       SYNCHRONIZE | FILE_WRITE_DATA,
    00103       &ObjectAttributes,
    00104       &IoStatus,
    00105       NULL,
    00106       FILE_ATTRIBUTE_NORMAL,
    00107       FILE_SHARE_READ,
    00108       (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
    00109       FILE_SYNCHRONOUS_IO_NONALERT,
    00110       NULL,
    00111       0 );
    00112
    00113     if ( !NT_SUCCESS( ntStatus ) )
    00114     {
    00115         IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);)
    00116
    00117         ExFreePool(FullFileName.Buffer);
    00118       Open->DumpFileHandle=NULL;
    00119         ntStatus = STATUS_NO_SUCH_FILE;
    00120         return ntStatus;
    00121     }
    00122
    00123    ExFreePool(FullFileName.Buffer);
    00124
    00125    ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
    00126       FILE_WRITE_ACCESS,
    00127       *IoFileObjectType,
    00128       KernelMode,
    00129       &Open->DumpFileObject,
    00130       0);
    00131
    00132     if ( !NT_SUCCESS( ntStatus ) )
    00133     {
    00134         IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
    00135
    00136       ZwClose( Open->DumpFileHandle );
    00137       Open->DumpFileHandle=NULL;
    00138
    00139         ntStatus = STATUS_NO_SUCH_FILE;
    00140         return ntStatus;
    00141     }
    00142
    00143     fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
    00144
    00145    IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
    00146
    00147    return ntStatus;
    00148 }
    00149
    00150 //-------------------------------------------------------------------
    00151
    00152 NTSTATUS
    00153 NPF_StartDump(POPEN_INSTANCE Open)
    00154 {
    00155    NTSTATUS ntStatus;
    00156    struct packet_file_header hdr;
    00157    IO_STATUS_BLOCK IoStatus;
    00158     NDIS_REQUEST pRequest;
    00159    ULONG MediaType;
    00160    OBJECT_ATTRIBUTES ObjectAttributes;
    00161
    00162     IF_LOUD(DbgPrint("NPF: StartDump.\n");)
    00163
    00164    // Init the file header
    00165    hdr.magic = TCPDUMP_MAGIC;
    00166    hdr.version_major = PCAP_VERSION_MAJOR;
    00167    hdr.version_minor = PCAP_VERSION_MINOR;
    00168    hdr.thiszone = 0; /*Currently not set*/
    00169    hdr.snaplen = 1514;
    00170    hdr.sigfigs = 0;
    00171
    00172    // Detect the medium type
    00173    switch (Open->Medium){
    00174
    00175    case NdisMediumWan:
    00176       hdr.linktype = DLT_EN10MB;
    00177       break;
    00178
    00179    case NdisMedium802_3:
    00180       hdr.linktype = DLT_EN10MB;
    00181       break;
    00182
    00183    case NdisMediumFddi:
    00184       hdr.linktype = DLT_FDDI;
    00185       break;
    00186
    00187    case NdisMedium802_5:
    00188       hdr.linktype = DLT_IEEE802;
    00189       break;
    00190
    00191    case NdisMediumArcnet878_2:
    00192       hdr.linktype = DLT_ARCNET;
    00193       break;
    00194
    00195    case NdisMediumAtm:
    00196       hdr.linktype = DLT_ATM_RFC1483;
    00197       break;
    00198
    00199    default:
    00200       hdr.linktype = DLT_EN10MB;
    00201    }
    00202
    00203    // Write the header.
    00204    // We can use ZwWriteFile because we are in the context of the application
    00205    ntStatus = ZwWriteFile(Open->DumpFileHandle,
    00206       NULL,
    00207       NULL,
    00208       NULL,
    00209       &IoStatus,
    00210       &hdr,
    00211       sizeof(hdr),
    00212       NULL,
    00213       NULL );
    00214
    00215
    00216     if ( !NT_SUCCESS( ntStatus ) )
    00217     {
    00218         IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
    00219
    00220       ZwClose( Open->DumpFileHandle );
    00221       Open->DumpFileHandle=NULL;
    00222
    00223         ntStatus = STATUS_NO_SUCH_FILE;
    00224         return ntStatus;
    00225     }
    00226
    00227    Open->DumpOffset.QuadPart=24;
    00228
    00229    ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
    00230       THREAD_ALL_ACCESS,
    00231       (ACCESS_MASK)0L,
    00232       0,
    00233       0,
    00234       NPF_DumpThread,
    00235       Open);
    00236
    00237     if ( !NT_SUCCESS( ntStatus ) )
    00238     {
    00239         IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
    00240
    00241       ZwClose( Open->DumpFileHandle );
    00242       Open->DumpFileHandle=NULL;
    00243
    00244         return ntStatus;
    00245     }
    00246
    00247    ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
    00248       THREAD_ALL_ACCESS,
    00249       NULL,
    00250       KernelMode,
    00251       &Open->DumpThreadObject,
    00252       0);
    00253
    00254     if ( !NT_SUCCESS( ntStatus ) )
    00255     {
    00256         IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
    00257
    00258       ObDereferenceObject(Open->DumpFileObject);
    00259       ZwClose( Open->DumpFileHandle );
    00260       Open->DumpFileHandle=NULL;
    00261
    00262         return ntStatus;
    00263     }
    00264
    00265
    00266    return ntStatus;
    00267
    00268 }
    00269
    00270 //-------------------------------------------------------------------
    00271 // Dump Thread
    00272 //-------------------------------------------------------------------
    00273
    00274 VOID NPF_DumpThread(POPEN_INSTANCE Open)
    00275 {
    00276    ULONG      FrozenNic;
    00277
    00278     IF_LOUD(DbgPrint("NPF: In the work routine.  Parameter = 0x%0x\n",Open);)
    00279
    00280    while(TRUE){
    00281
    00282       // Wait until some packets arrive or the timeout expires
    00283       NdisWaitEvent(&Open->DumpEvent, 5000);
    00284
    00285       IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
    00286
    00287       if(Open->DumpLimitReached ||
    00288          Open->Size==0){      // BufSize=0 means that this instance was closed, or that the buffer is too
    00289                            // small for any capture. In both cases it is better to end the dump
    00290
    00291          IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
    00292          IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);)
    00293
    00294          PsTerminateSystemThread(STATUS_SUCCESS);
    00295          return;
    00296       }
    00297
    00298       NdisResetEvent(&Open->DumpEvent);
    00299
    00300       // Write the content of the buffer to the file
    00301       if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){
    00302          PsTerminateSystemThread(STATUS_SUCCESS);
    00303          return;
    00304       }
    00305
    00306    }
    00307
    00308 }
    00309
    00310 //-------------------------------------------------------------------
    00311
    00312 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
    00313 {
    00314    UINT      Thead;
    00315    UINT      Ttail;
    00316    UINT      TLastByte;
    00317    PUCHAR      CurrBuff;
    00318    NTSTATUS   ntStatus;
    00319    IO_STATUS_BLOCK IoStatus;
    00320     PMDL      lMdl;
    00321    UINT      SizeToDump;
    00322
    00323 #if 0
    00324
    00325    Thead=Open->Bhead;
    00326    Ttail=Open->Btail;
    00327    TLastByte=Open->BLastByte;
    00328
    00329     IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
    00330
    00331    // Get the address of the buffer
    00332    CurrBuff=Open->Buffer;
    00333    //
    00334    // Fill the application buffer
    00335    //
    00336    if( Ttail < Thead )
    00337    {
    00338       if(Open->MaxDumpBytes &&
    00339          (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
    00340       {
    00341          // Size limit reached
    00342          UINT PktLen;
    00343
    00344          SizeToDump = 0;
    00345
    00346          // Scan the buffer to detect the exact amount of data to save
    00347          while(TRUE){
    00348             PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
    00349
    00350             if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
    00351                break;
    00352
    00353             SizeToDump += PktLen;
    00354          }
    00355
    00356       }
    00357       else
    00358          SizeToDump = TLastByte-Thead;
    00359
    00360       lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
    00361       if (lMdl == NULL)
    00362       {
    00363          // No memory: stop dump
    00364          IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
    00365          return STATUS_UNSUCCESSFUL;
    00366       }
    00367
    00368       MmBuildMdlForNonPagedPool(lMdl);
    00369
    00370       // Write to disk
    00371       NPF_WriteDumpFile(Open->DumpFileObject,
    00372          &Open->DumpOffset,
    00373          SizeToDump,
    00374          lMdl,
    00375          &IoStatus);
    00376
    00377       IoFreeMdl(lMdl);
    00378
    00379       if(!NT_SUCCESS(IoStatus.Status)){
    00380          // Error
    00381          return STATUS_UNSUCCESSFUL;
    00382       }
    00383
    00384       if(SizeToDump != TLastByte-Thead){
    00385          // Size limit reached.
    00386          Open->DumpLimitReached = TRUE;
    00387
    00388          // Awake the application
    00389          KeSetEvent(Open->ReadEvent,0,FALSE);
    00390
    00391          return STATUS_UNSUCCESSFUL;
    00392       }
    00393
    00394       // Update the packet buffer
    00395       Open->DumpOffset.QuadPart+=(TLastByte-Thead);
    00396       Open->BLastByte=Ttail;
    00397       Open->Bhead=0;
    00398    }
    00399
    00400    if( Ttail > Thead ){
    00401
    00402       if(Open->MaxDumpBytes &&
    00403          (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
    00404       {
    00405          // Size limit reached
    00406          UINT PktLen;
    00407
    00408          SizeToDump = 0;
    00409
    00410          // Scan the buffer to detect the exact amount of data to save
    00411          while(Thead + SizeToDump < Ttail){
    00412
    00413             PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
    00414
    00415             if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
    00416                break;
    00417
    00418             SizeToDump += PktLen;
    00419          }
    00420
    00421       }
    00422       else
    00423          SizeToDump = Ttail-Thead;
    00424
    00425       lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
    00426       if (lMdl == NULL)
    00427       {
    00428          // No memory: stop dump
    00429          IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
    00430          return STATUS_UNSUCCESSFUL;
    00431       }
    00432
    00433       MmBuildMdlForNonPagedPool(lMdl);
    00434
    00435       // Write to disk
    00436       NPF_WriteDumpFile(Open->DumpFileObject,
    00437          &Open->DumpOffset,
    00438          SizeToDump,
    00439          lMdl,
    00440          &IoStatus);
    00441
    00442       IoFreeMdl(lMdl);
    00443
    00444       if(!NT_SUCCESS(IoStatus.Status)){
    00445          // Error
    00446          return STATUS_UNSUCCESSFUL;
    00447       }
    00448
    00449       if(SizeToDump != Ttail-Thead){
    00450          // Size limit reached.
    00451          Open->DumpLimitReached = TRUE;
    00452
    00453          // Awake the application
    00454          KeSetEvent(Open->ReadEvent,0,FALSE);
    00455
    00456          return STATUS_UNSUCCESSFUL;
    00457       }
    00458
    00459       // Update the packet buffer
    00460       Open->DumpOffset.QuadPart+=(Ttail-Thead);
    00461       Open->Bhead=Ttail;
    00462
    00463    }
    00464 #endif
    00465    return STATUS_SUCCESS;
    00466 }
    00467
    00468 //-------------------------------------------------------------------
    00469
    00470 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
    00471    NTSTATUS   ntStatus;
    00472    IO_STATUS_BLOCK IoStatus;
    00473     PMDL      WriteMdl;
    00474     PUCHAR      VMBuff;
    00475    UINT      VMBufLen;
    00476
    00477 #if 0
    00478     IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
    00479     IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
    00480
    00481 DbgPrint("1\n");
    00482    // Consistency check
    00483    if(Open->DumpFileHandle == NULL)
    00484       return STATUS_UNSUCCESSFUL;
    00485
    00486 DbgPrint("2\n");
    00487    ZwClose( Open->DumpFileHandle );
    00488
    00489    ObDereferenceObject(Open->DumpFileObject);
    00490 /*
    00491    if(Open->DumpLimitReached == TRUE)
    00492       // Limit already reached: don't save the rest of the buffer.
    00493       return STATUS_SUCCESS;
    00494 */
    00495 DbgPrint("3\n");
    00496
    00497    NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
    00498
    00499    // Flush the buffer to file
    00500    NPF_SaveCurrentBuffer(Open);
    00501
    00502    // Close The file
    00503    ObDereferenceObject(Open->DumpFileObject);
    00504    ZwClose( Open->DumpFileHandle );
    00505
    00506    Open->DumpFileHandle = NULL;
    00507
    00508    ObDereferenceObject(Open->DumpFileObject);
    00509 #endif
    00510    return STATUS_SUCCESS;
    00511 }
    00512
    00513 //-------------------------------------------------------------------
    00514
    00515 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
    00516                                 PIRP Irp,
    00517                                 PVOID Context)
    00518 {
    00519
    00520     // Copy the status information back into the "user" IOSB
    00521     *Irp->UserIosb = Irp->IoStatus;
    00522
    00523     // Wake up the mainline code
    00524     KeSetEvent(Irp->UserEvent, 0, FALSE);
    00525
    00526     return STATUS_MORE_PROCESSING_REQUIRED;
    00527 }
    00528
    00529 //-------------------------------------------------------------------
    00530
    00531 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
    00532                              PLARGE_INTEGER Offset,
    00533                         ULONG Length,
    00534                         PMDL Mdl,
    00535                         PIO_STATUS_BLOCK IoStatusBlock)
    00536 {
    00537     PIRP irp;
    00538     KEVENT event;
    00539     PIO_STACK_LOCATION ioStackLocation;
    00540     PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
    00541     NTSTATUS Status;
    00542
    00543     // Set up the event we'll use
    00544     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    00545
    00546     // Allocate and build the IRP we'll be sending to the FSD
    00547     irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
    00548
    00549     if (!irp) {
    00550         // Allocation failed, presumably due to memory allocation failure
    00551         IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
    00552         IoStatusBlock->Information = 0;
    00553
    00554       return;
    00555     }
    00556
    00557     irp->MdlAddress = Mdl;
    00558     irp->UserEvent = &event;
    00559     irp->UserIosb = IoStatusBlock;
    00560     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00561     irp->Tail.Overlay.OriginalFileObject= FileObject;
    00562     irp->RequestorMode = KernelMode;
    00563
    00564     // Indicate that this is a WRITE operation
    00565     irp->Flags = IRP_WRITE_OPERATION;
    00566
    00567     // Set up the next I/O stack location
    00568     ioStackLocation = IoGetNextIrpStackLocation(irp);
    00569     ioStackLocation->MajorFunction = IRP_MJ_WRITE;
    00570     ioStackLocation->MinorFunction = 0;
    00571     ioStackLocation->DeviceObject = fsdDevice;
    00572     ioStackLocation->FileObject = FileObject;
    00573     IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
    00574     ioStackLocation->Parameters.Write.Length = Length;
    00575     ioStackLocation->Parameters.Write.ByteOffset = *Offset;
    00576
    00577
    00578     // Send it on.  Ignore the return code
    00579     (void) IoCallDriver(fsdDevice, irp);
    00580
    00581     // Wait for the I/O to complete.
    00582     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
    00583
    00584     // Free the IRP now that we are done with it
    00585     IoFreeIrp(irp);
    00586
    00587     return;
    00588
    00589 }

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.