⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 read.c

📁 Windows XP下的抓包程序实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
 * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
 * 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, CACE Technologies 
 * 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 <stdarg.h>
#include "ntddk.h"
#include <ntiologc.h>
#include <ndis.h>
#include "debug.h"
#include "packet.h"
#include "win_bpf.h"

#include "tme.h"
#include "time_calls.h"

extern struct time_conv G_Start_Time; // from openclos.c

extern ULONG NCpu; //from packet.c

NTSTATUS NPF_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
    POPEN_INSTANCE      Open;
    PIO_STACK_LOCATION  IrpSp;
    PUCHAR				packp;
	ULONG				Input_Buffer_Length;
	UINT				Thead;
	UINT				Ttail;
	UINT				TLastByte;
	PUCHAR				CurrBuff;
	LARGE_INTEGER		CapTime;
	LARGE_INTEGER		TimeFreq;
	struct bpf_hdr		*header;
	KIRQL				Irql;
	PUCHAR				UserPointer;
	ULONG				bytecopy;
	UINT				SizeToCopy;
	UINT				PktLen;
	ULONG				copied,count,current_cpu,av,plen,increment,ToCopy,available;
	CpuPrivateData		*LocalData;
	ULONG				i;
	ULONG				Occupation;

	IF_LOUD(DbgPrint("NPF: Read\n");)

		
	IrpSp = IoGetCurrentIrpStackLocation(Irp);
    Open=IrpSp->FileObject->FsContext;

	//
	// we need to test if the device is still bound to the Network adapter,
	// so we perform a start/stop using binding.
	// This is not critical, since we just want to have a quick way to have the
	// dispatch read fail in case the adapter has been unbound

	if(NPF_StartUsingBinding(Open) == FALSE)
	{
		// The Network adapter has been removed or diasabled
		EXIT_FAILURE(0);
	}
	NPF_StopUsingBinding(Open);

	if (Open->Size == 0)	
	{
		EXIT_FAILURE(0);
	}

	if( Open->mode & MODE_DUMP && Open->DumpFileHandle == NULL ){  
		// this instance is in dump mode, but the dump file has still not been opened
		EXIT_FAILURE(0);
	}
	
	Occupation=0;

	for(i=0;i<NCpu;i++)
		Occupation += (Open->Size - Open->CpuData[i].Free);
	
	//See if the buffer is full enough to be copied
	if( Occupation <= Open->MinToCopy*NCpu || Open->mode & MODE_DUMP )
	{
		if (Open->ReadEvent != NULL)
		{
			//wait until some packets arrive or the timeout expires		
			if(Open->TimeOut.QuadPart != (LONGLONG)IMMEDIATE)
				KeWaitForSingleObject(Open->ReadEvent,
					UserRequest,
					KernelMode,
					TRUE,
					(Open->TimeOut.QuadPart == (LONGLONG)0)? NULL: &(Open->TimeOut));

			KeClearEvent(Open->ReadEvent);
		}		

		if(Open->mode & MODE_STAT)
		{   //this capture instance is in statistics mode
#ifdef NDIS50
			CurrBuff=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
#else
			CurrBuff=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif

			if (CurrBuff == NULL)
			{
				EXIT_FAILURE(0);
			}


			//fill the bpf header for this packet
			header=(struct bpf_hdr*)CurrBuff;
			GET_TIME(&header->bh_tstamp,&G_Start_Time);

			if(Open->mode & MODE_DUMP){
				*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+16)=Open->DumpOffset.QuadPart;
				header->bh_caplen=24;
				header->bh_datalen=24;
				Irp->IoStatus.Information = 24 + sizeof(struct bpf_hdr);
			}
			else{
				header->bh_caplen=16;
				header->bh_datalen=16;
				header->bh_hdrlen=sizeof(struct bpf_hdr);
				Irp->IoStatus.Information = 16 + sizeof(struct bpf_hdr);
			}

			*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr))=Open->Npackets.QuadPart;
			*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+8)=Open->Nbytes.QuadPart;
			
			//reset the countetrs
			NdisAcquireSpinLock( &Open->CountersLock );
			Open->Npackets.QuadPart=0;
			Open->Nbytes.QuadPart=0;
			NdisReleaseSpinLock( &Open->CountersLock );
			
			Irp->IoStatus.Status = STATUS_SUCCESS;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			
			return STATUS_SUCCESS;
		}
		
//
// The MONITOR_MODE (aka TME extensions) is not supported on 
// 64 bit architectures
//
#ifdef __NPF_x86__

		if(Open->mode==MODE_MON)   //this capture instance is in monitor mode
		{   
			PTME_DATA data;
			ULONG cnt;
			ULONG block_size;
			PUCHAR tmp;

#ifdef NDIS50
			UserPointer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
#else
			UserPointer=MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif

			if (UserPointer == NULL)
			{
				EXIT_FAILURE(0);
			}

			if ((!IS_VALIDATED(Open->tme.validated_blocks,Open->tme.active_read))||(IrpSp->Parameters.Read.Length<sizeof(struct bpf_hdr)))
			{	
				EXIT_FAILURE(0);
			}
			
			header=(struct bpf_hdr*)UserPointer;
	
			GET_TIME(&header->bh_tstamp,&G_Start_Time);

			
			header->bh_hdrlen=sizeof(struct bpf_hdr);
	

			//moves user memory pointer
			UserPointer+=sizeof(struct bpf_hdr);
			
			//calculus of data to be copied
			//if the user buffer is smaller than data to be copied,
			//only some data will be copied
			data=&Open->tme.block_data[Open->tme.active_read];

			if (data->last_read.tv_sec!=0)
				data->last_read=header->bh_tstamp;
			

			bytecopy=data->block_size*data->filled_blocks;
			
			if ((IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))<bytecopy)
				bytecopy=(IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))/ data->block_size;
			else 
				bytecopy=data->filled_blocks;

			tmp=data->shared_memory_base_address;
			block_size=data->block_size;
			
			for (cnt=0;cnt<bytecopy;cnt++)
			{
				NdisAcquireSpinLock(&Open->MachineLock);
				RtlCopyMemory(UserPointer,tmp,block_size);
				NdisReleaseSpinLock(&Open->MachineLock);
				tmp+=block_size;
				UserPointer+=block_size;
			}
						
			bytecopy*=block_size;

			header->bh_caplen=bytecopy;
			header->bh_datalen=header->bh_caplen;

			EXIT_SUCCESS(bytecopy+sizeof(struct bpf_hdr));
		}

		Occupation=0;

		for(i=0;i<NCpu;i++)
			Occupation += (Open->Size - Open->CpuData[i].Free);


		if ( Occupation == 0 || Open->mode & MODE_DUMP)
			// The timeout has expired, but the buffer is still empty (or the packets must be written to file).
			// We must awake the application, returning an empty buffer.
		{
			EXIT_SUCCESS(0);
		}
				
	#else // not __NPF_x86__ , so x86-64 or IA64
		if(Open->mode==MODE_MON)   //this capture instance is in monitor mode
		{   
			EXIT_FAILURE(0);
		}
	#endif // __NPF_x86__

	}



//------------------------------------------------------------------------------
	copied=0;
	count=0;
	current_cpu=0;
	available = IrpSp->Parameters.Read.Length;
#ifdef NDIS50
	packp=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
#else
	packp=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif

	if (packp == NULL)
	{
		EXIT_FAILURE(0);
	}

	if (Open->ReadEvent != NULL)
		KeClearEvent(Open->ReadEvent);

	while (count < NCpu) //round robin on the CPUs, if count = NCpu there are no packets left to be copied
	{
		if (available == copied)
		{
			EXIT_SUCCESS(copied);
		}
		
		LocalData = &Open->CpuData[current_cpu];

		if (LocalData->Free < Open->Size)  
		{  //there are some packets in the selected (aka LocalData) buffer
			struct PacketHeader *Header = (struct PacketHeader*)(LocalData->Buffer + LocalData->C);

			if ( Header->SN == Open->ReaderSN)
			{   //check if it the next one to be copied
				plen = Header->header.bh_caplen;
				if (plen + sizeof (struct bpf_hdr) > available - copied)  
				{  //if the packet does not fit into the user buffer, we've ended copying packets
					EXIT_SUCCESS(copied);
				}
				
//				FIX_TIMESTAMPS(&Header->header.bh_tstamp);

				*((struct bpf_hdr*)(&packp[copied]))=Header->header;
				
				copied += sizeof(struct bpf_hdr);
				LocalData->C += sizeof(struct PacketHeader);

				if (LocalData->C == Open->Size)
					LocalData->C = 0;

				if (Open->Size - LocalData->C < plen)
				{
					//the packet is fragmented in the buffer (i.e. it skips the buffer boundary)
					ToCopy = Open->Size - LocalData->C;
					RtlCopyMemory(packp + copied,LocalData->Buffer + LocalData->C,ToCopy);
					RtlCopyMemory(packp + copied + ToCopy,LocalData->Buffer,plen-ToCopy);
					LocalData->C = plen-ToCopy;
				}
				else
				{
					//the packet is not fragmented
					RtlCopyMemory(packp + copied ,LocalData->Buffer + LocalData->C ,plen);
					LocalData->C += plen;
			//		if (c==size)  inutile, contemplato nell "header atomico"
			//			c=0;
				}

				Open->ReaderSN++;
				copied+=Packet_WORDALIGN(plen);

				increment = plen + sizeof(struct PacketHeader);
				if ( Open->Size - LocalData->C < sizeof(struct PacketHeader))
				{   //the next packet would be saved at the end of the buffer, but the NewHeader struct would be fragmented
					//so the producer (--> the consumer) skips to the beginning of the buffer
					increment += Open->Size-LocalData->C;
					LocalData->C=0;
				}
				InterlockedExchangeAdd(&Open->CpuData[current_cpu].Free,increment);
				count=0;
			}
			else
			{
				current_cpu=(current_cpu+1)%NCpu;
				count++;	
			}
		
		}
		else
		{
			current_cpu=(current_cpu+1)%NCpu;
			count++;	
		}
	}
		
	{EXIT_SUCCESS(copied);}

//------------------------------------------------------------------------------

}

NDIS_STATUS NPF_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE MacReceiveContext,
                        IN PVOID HeaderBuffer,IN UINT HeaderBufferSize,IN PVOID LookaheadBuffer,
                        IN UINT LookaheadBufferSize,IN UINT PacketSize)
{
    POPEN_INSTANCE      Open;
    PNDIS_PACKET        pPacket;
    ULONG               SizeToTransfer;
    NDIS_STATUS         Status;
    UINT                BytesTransfered;
    ULONG               BufferLength;
    PMDL                pMdl1,pMdl2;
	LARGE_INTEGER		CapTime;
	LARGE_INTEGER		TimeFreq;
	UINT				fres;
	USHORT				NPFHdrSize;

	CpuPrivateData		*LocalData;
	ULONG				Cpu;
	struct PacketHeader	*Header;
	ULONG				ToCopy;
	ULONG				increment;
	ULONG				i;
	BOOLEAN				ShouldReleaseBufferLock;

    IF_VERY_LOUD(DbgPrint("NPF: tap\n");)
	IF_VERY_LOUD(DbgPrint("HeaderBufferSize=%u, LookAheadBuffer=%p, LookaheadBufferSize=%u, PacketSize=%u\n", 
	HeaderBufferSize,
	LookaheadBuffer,
	LookaheadBufferSize,
	PacketSize);)

	Open= (POPEN_INSTANCE)ProtocolBindingContext;
	
    Cpu = KeGetCurrentProcessorNumber();
	LocalData = &Open->CpuData[Cpu];

	LocalData->Received++;
	IF_LOUD(DbgPrint("Received on CPU %d \t%d\n",Cpu,LocalData->Received);)
//	Open->Received++;		// Number of packets received by filter ++

	NdisAcquireSpinLock(&Open->MachineLock);

	//
	//Check if the lookahead buffer follows the mac header.
	//If the data follow the header (i.e. there is only a buffer) a normal bpf_filter() is
	//executed on the packet.
	//Otherwise if there are 2 separate buffers (this could be the case of LAN emulation or
	//things like this) bpf_filter_with_2_buffers() is executed.
	//
	if((UINT)((PUCHAR)LookaheadBuffer-(PUCHAR)HeaderBuffer) != HeaderBufferSize)
		fres=bpf_filter_with_2_buffers((struct bpf_insn*)(Open->bpfprogram),
									   HeaderBuffer,
									   LookaheadBuffer,
									   HeaderBufferSize,
									   PacketSize+HeaderBufferSize,
									   LookaheadBufferSize+HeaderBufferSize,
									   &Open->mem_ex,
									   &Open->tme,
									   &G_Start_Time);
	
	
	else 
//
// the jit filter is available on x86 (32 bit) only
//
#ifdef __NPF_x86__

		if(Open->Filter != NULL)
		{
			if (Open->bpfprogram != NULL)
			{
				fres=Open->Filter->Function(HeaderBuffer,
									PacketSize+HeaderBufferSize,
									LookaheadBufferSize+HeaderBufferSize);
			}
			else
				fres = -1;
		}
		else
#endif //__NPF_x86__
			fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram),
 		                HeaderBuffer,
 						PacketSize+HeaderBufferSize,
						LookaheadBufferSize+HeaderBufferSize,
						&Open->mem_ex,
						&Open->tme,
						&G_Start_Time);

	NdisReleaseSpinLock(&Open->MachineLock);

//
// The MONITOR_MODE (aka TME extensions) is not supported on 
// 64 bit architectures
//
#ifdef __NPF_x86__
	if(Open->mode==MODE_MON)
	// we are in monitor mode
	{
		if (fres==1) 
		{
			if (Open->ReadEvent != NULL)
			{
				KeSetEvent(Open->ReadEvent,0,FALSE);	
			}
		}
		return NDIS_STATUS_NOT_ACCEPTED;

	}
#endif

	if(fres==0)
	{
		// Packet not accepted by the filter, ignore it.
		return NDIS_STATUS_NOT_ACCEPTED;
	}

	//if the filter returns -1 the whole packet must be accepted
	if(fres == -1 || fres > PacketSize+HeaderBufferSize)
		fres = PacketSize+HeaderBufferSize; 

	if(Open->mode & MODE_STAT)
	{
	// we are in statistics mode
		NdisAcquireSpinLock( &Open->CountersLock );

		Open->Npackets.QuadPart++;
		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -