庖丁解牛-----winpcap源码彻底解密(二)
查找到网卡后,open网卡,设置过滤器,然后就该读写数据包了,下面就讲讲怎么发送和接收数据包了。
(4)pcap_sendpacket
pcap_sendpacket用来发送数据包,该函数只能发送单个的数据包,
int pcap_sendpacket(pcap_t *p, const u_char *buf, intsize)
{
if (p->inject_op(p,buf, size) == -1)
return (-1);
return (0);
}
p->inject_op =pcap_inject_win32;
/* Send a packet to the network */
staticint pcap_inject_win32(pcap_t *p,const void *buf,size_t size){
LPPACKET PacketToSend;
PacketToSend=PacketAllocatePacket();
if (PacketToSend ==NULL)
{
snprintf(p->errbuf,PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed");
return -1;
}
PacketInitPacket(PacketToSend,(PVOID)buf,size);
if(PacketSendPacket(p->adapter,PacketToSend,TRUE) ==FALSE){
snprintf(p->errbuf,PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
PacketFreePacket(PacketToSend);
return -1;
}
PacketFreePacket(PacketToSend);
/*
* We assume it all got sent if "PacketSendPacket()" succeeded.
* "pcap_inject()" is expected to return the number of bytes
* sent.
*/
return size;
}
Pcap_inject_win32函数调用ParketSendPacket将数据包转发到Parket.dll,下面就看看ParketSendPacket的源码:
//发送单个包
BOOLEANPacketSendPacket(LPADAPTERAdapterObject,LPPACKETlpPacket,BOOLEANSync)
{
DWORD BytesTransfered;
BOOLEAN Result;
TRACE_ENTER("PacketSendPacket");
UNUSED(Sync);
#ifdefHAVE_AIRPCAP_API
if(AdapterObject->Flags ==INFO_FLAG_AIRPCAP_CARD)
{
if(g_PAirpcapWrite)
{
Result = (BOOLEAN)g_PAirpcapWrite(AdapterObject->AirpcapAd,lpPacket->Buffer,lpPacket->Length);
TRACE_EXIT("PacketSetMinToCopy");
return Result;
}
else
{
TRACE_EXIT("PacketSetMinToCopy");
TRACE_PRINT("Transmission not supported with this version of AirPcap");
return FALSE;
}
}
#endif// HAVE_AIRPCAP_API
#ifdefHAVE_WANPACKET_API
if(AdapterObject->Flags ==INFO_FLAG_NDISWAN_ADAPTER)
{
TRACE_PRINT("PacketSendPacket: packet sending not allowed on wan adapters");
TRACE_EXIT("PacketSendPacket");
return FALSE;
}
#endif// HAVE_WANPACKET_API
#ifdefHAVE_NPFIM_API
if(AdapterObject->Flags == INFO_FLAG_NPFIM_DEVICE)
{
TRACE_PRINT("PacketSendPacket: packet sending not allowed on NPFIM adapters");
TRACE_EXIT("PacketSendPacket");
return FALSE;
}
#endif//HAVE_NPFIM_API
if (AdapterObject->Flags ==INFO_FLAG_NDIS_ADAPTER)
{
Result = (BOOLEAN)WriteFile(AdapterObject->hFile,lpPacket->Buffer,lpPacket->Length,&BytesTransfered,NULL);
}
else
{
TRACE_PRINT1("Request to write on an unknown device type (%u)",AdapterObject->Flags);
Result = FALSE;
}
TRACE_EXIT("PacketSendPacket");
return Result;
}
PacketSendPacket通过WriteFile将数据包转发出去。PacketSendPacket是parket.dll,WriteFile对应驱动中
NTSTATUS
NPF_Write(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PNDIS_PACKET pPacket;
NDIS_STATUS Status;
ULONG NumSends;
ULONG numSentPackets;
TRACE_ENTER();
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
if (NPF_StartUsingOpenInstance(Open) == FALSE)
{
//
// an IRP_MJ_CLEANUP was received, just fail the request
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_CANCELLED;
}
NumSends = Open->Nwrites;
//
// validate the send parameters set by the IOCTL
//
if (NumSends == 0)
{
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_SUCCESS;
}
//
// Validate input parameters:
// 1. The packet size should be greater than 0,
// 2. less-equal than max frame size for the link layer and
// 3. the maximum frame size of the link layer should not be zero.
//
if(IrpSp->Parameters.Write.Length == 0 || // Check that the buffer provided by the user is not empty
Open->MaxFrameSize == 0 || // Check that the MaxFrameSize is correctly initialized
Irp->MdlAddress == NULL ||
IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Frame size out of range, or maxFrameSize = 0. Send aborted");
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_UNSUCCESSFUL;
}
//
// Increment the ref counter of the binding handle, if possible
//
if(NPF_StartUsingBinding(Open) == FALSE)
{
TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Adapter is probably unbinding, cannot send packets");
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_INVALID_DEVICE_REQUEST;
}
NdisAcquireSpinLock(&Open->WriteLock);
if(Open->WriteInProgress)
{
// Another write operation is currently in progress
NdisReleaseSpinLock(&Open->WriteLock);
NPF_StopUsingBinding(Open);
TRACE_MESSAGE(PACKET_DEBUG_LOUD,"Another Send operation is in progress, aborting.");
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_UNSUCCESSFUL;
}
else
{
Open->WriteInProgress = TRUE;
NdisResetEvent(&Open->NdisWriteCompleteEvent);
}
NdisReleaseSpinLock(&Open->WriteLock);
TRACE_MESSAGE2(PACKET_DEBUG_LOUD,"Max frame size = %u, packet size = %u", Open->MaxFrameSize, IrpSp->Parameters.Write.Length);
//
// reset the number of packets pending the SendComplete
//
Open->TransmitPendingPackets = 0;
NdisResetEvent(&Open->WriteEvent);
numSentPackets = 0;
while( numSentPackets < NumSends )
{
NdisAllocatePacket(
&Status,
&pPacket,
Open->PacketPool
);
if (Status == NDIS_STATUS_SUCCESS)
{
//
// packet is available, prepare it and send it with NdisSend.
//
//
// If asked, set the flags for this packet.
// Currently, the only situation in which we set the flags is to disable the reception of loopback
// packets, i.e. of the packets sent by us.
//
if(Open->SkipSentPackets)
{
NdisSetPacketFlags(
pPacket,
g_SendPacketFlags);
}
// The packet hasn't a buffer that needs not to be freed after every single write
RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
// // Save the IRP associated with the packet
// RESERVED(pPacket)->Irp=Irp;
// Attach the writes buffer to the packet
NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
InterlockedIncrement(&Open->TransmitPendingPackets);
NdisResetEvent(&Open->NdisWriteCompleteEvent);
//
// Call the MAC 调用NdisSend发送包
//
NdisSend(
&Status,
Open->AdapterHandle,
pPacket);
if (Status != NDIS_STATUS_PENDING)
{
// The send didn't pend so call the completion handler now
NPF_SendComplete(
Open,
pPacket,
Status
);
}
numSentPackets ++;
}
else
{
//
// no packets are available in the Transmit pool, wait some time. The
// event gets signalled when at least half of the TX packet pool packets
// are available
//
NdisWaitEvent(&Open->WriteEvent,1);
}
}
//
// when we reach this point, all the packets have been enqueued to NdisSend,
// we just need to wait for all the packets to be completed by the SendComplete
// (if any of the NdisSend requests returned STATUS_PENDING)
//
NdisWaitEvent(&Open->NdisWriteCompleteEvent, 0);
//
// all the packets have been transmitted, release the use of the adapter binding
//
NPF_StopUsingBinding(Open);
//
// no more writes are in progress
//
NdisAcquireSpinLock(&Open->WriteLock);
Open->WriteInProgress = FALSE;
NdisReleaseSpinLock(&Open->WriteLock);
NPF_StopUsingOpenInstance(Open);
//
// Complete the Irp and return success
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = IrpSp->Parameters.Write.Length;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
TRACE_EXIT();
return STATUS_SUCCESS;
}