庖丁解牛-----winpcap源码彻底解密(二)

来源:互联网 发布:张予曦的淘宝店转让 编辑:程序博客网 时间:2024/05/21 18:43

庖丁解牛-----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 */

staticintpcap_inject_win32(pcap_t *p,constvoid *buf,size_tsize){

    LPPACKETPacketToSend;

    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.

     */

    returnsize;

}

 

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");

             

             returnResult;

        }

        else

        {

             TRACE_EXIT("PacketSetMinToCopy");

             TRACE_PRINT("Transmission not supported with this version of AirPcap");

             returnFALSE;

        }

    }

#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");

        returnFALSE;

    }

#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");

    returnResult;

}

PacketSendPacket通过WriteFile将数据包转发出去。PacketSendPacketparket.dllWriteFile对应驱动中

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;

}

 

原创粉丝点击