阅读:2969回复:10
如何取得以太包的包头??大赏50分
我用以下方法取得包头,并且过滤ICMP包,好像没用!
NDIS_STATUS PtReceive( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: LBFO - need to use primary for all receives Arguments: Return Value: --*/ { PADAPT pAdapt =(PADAPT)ProtocolBindingContext; PNDIS_PACKET MyPacket, Packet; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; //UINT PhysicalBufferCount, BufferCount,TotalPacketLength; //PNDIS_BUFFER *FirstBuffer; PVOID virtualAddress; PNDIS_BUFFER firstBuffer, nextBuffer; ULONG totalLength; if(!pAdapt->MiniportHandle) { Status = NDIS_STATUS_FAILURE; } else do { // // We should not be getting Receives on a Secondary, this is just specific to our LBFO driver // if(pAdapt->isSecondary) { DBGPRINT("PASSTHRU GETTING RECIEVES ON SECONDARY\n"); ASSERT(0); } // // If this was indicated by the miniport below as a packet, then get that packet pointer and indicate // it as a packet as well(with appropriate status). This way the OOB stuff is accessible to the // transport above us. // Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext); if(Packet != NULL) { NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength); while( firstBuffer != NULL) { NdisQueryBuffer(firstBuffer, &virtualAddress, &totalLength); if(!virtualAddress) { // // System is running low on memory resources. // So fail the read. // //status = STATUS_INSUFFICIENT_RESOURCES; //goto CleanExit; break; } else { if ((((char*)virtualAddress)[12] == 8)&& (((char*)virtualAddress)[13] == 0)&& (((char*)virtualAddress)[23] == 1)) { Status = NDIS_STATUS_FAILURE; return Status; } } NdisGetNextBuffer(firstBuffer, &nextBuffer); firstBuffer = nextBuffer; } // // Get a packet off the pool and indicate that up // NdisDprAllocatePacket(&Status, &MyPacket, pAdapt->RecvPacketPoolHandle); if(Status == NDIS_STATUS_SUCCESS) { MyPacket->Private.Head = Packet->Private.Head; MyPacket->Private.Tail = Packet->Private.Tail; // // Get the original packet(it could be the same packet as one received or a different one // based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible // correctly at the top. // NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet)); NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize); // // Set Packet Flags // NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet); // // Make sure the status is set to NDIS_STATUS_RESOURCES. // NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES); NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1); ASSERT(NDIS_GET_PACKET_STATUS(MyPacket) == NDIS_STATUS_RESOURCES); NdisDprFreePacket(MyPacket); break; } } // // Fall through if the miniport below us has either not indicated a packet or we could not // allocate one // pAdapt->IndicateRcvComplete = TRUE; switch(pAdapt->Medium) { case NdisMedium802_3: NdisMEthIndicateReceive(pAdapt->MiniportHandle, MacReceiveContext, HeaderBuffer, HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize, PacketSize); break; case NdisMedium802_5: NdisMTrIndicateReceive(pAdapt->MiniportHandle, MacReceiveContext, HeaderBuffer, HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize, PacketSize); break; case NdisMediumFddi: NdisMFddiIndicateReceive(pAdapt->MiniportHandle, MacReceiveContext, HeaderBuffer, HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize, PacketSize); break; default: ASSERT(0); break; } } while(FALSE); return Status; } |
|
|
沙发#
发布于:2001-08-13 14:30
好多分呀!
你这个例程运行了吗? |
|
|
板凳#
发布于:2001-08-13 16:25
{
if ((((char*)virtualAddress)[12] == 8)&& (((char*)virtualAddress)[13] == 0)&& (((char*)virtualAddress)[23] == 1)) { Status = NDIS_STATUS_FAILURE; return Status; } 你在这里对这个包处理,不知你具体想干什么?你是不是不想让本机收到这个包呀!如果是这样,你并不能阻止,此包依然能上传,你若要阻止,可试着改一下MAC地址,这样系统认为不是发向本机的数据而抛弃,可能可行! |
|
地板#
发布于:2001-08-13 16:41
按照你的程序当buffer chain上的
first buffer的长度小于23时 if ((((char*)virtualAddress)[12] == 8)&& (((char*)virtualAddress)[13] == 0)&& (((char*)virtualAddress)[23] == 1)) 这个判断就会出问题 另外你的那个 do while有什么意义啊 |
|
|
地下室#
发布于:2001-08-13 16:57
是这样的,我只是想做一个拦截ICMP包的例子,开始以为GET..NEXT取得是下一个包,后来发现是一个包的不同部分。哪请问,直接用:
NdisGetFirstBufferFromPacket(Packet,&pFirstBuffer,&pVirtualAddress, &iFirstBufferLength,&iTotalLength); if ((((char*)pVirtualAddress)[12] == 8)&& (((char*)pVirtualAddress)[13] == 0)) return NDIS_STATUS_FAILURE; 可否拦截所有的IP包? 另外如何使IMD DRIVER与应用程序通讯? |
|
|
5楼#
发布于:2001-08-13 18:40
有没有可能是NDIS是传递给你的IM一个Packet的描述符,调用了你的PtReceivePacket例程.
|
|
|
6楼#
发布于:2001-08-13 20:03
我的QQ:15614487
个人主页:www.ishacker.com 请版本和各位高人指教啊! |
|
|
7楼#
发布于:2001-08-15 14:01
一个packet的buffer不是一个区域
应该是一个buffer chain 你的写法实际上只是对这个buffer chain上的第一个 buffer进行了判断当第一个buffer的长度大于13时没有问题, 但是当一个buffer小于这个长度就不对了 你应该判断一下如果不够用getnextbuffer取出下一段 平到一起判断, 具体的packet结构ddk上有专门的描述 |
|
|
8楼#
发布于:2001-08-16 18:42
网卡驱动程序可能通过两种方式向协议通知接收到数据包,
1.PtReceive,PtTransferDataComplete,还可能有PtReceiveComplete(非一一对应,可以不考虑) 2.PtReceivePacket 方法1常用于使用从dma方式的网卡, 方法2常用于使用主dma方式的网卡。 在方法1中,PtReceive给出了网络帧的头14字节和LookAhead部分(长度不定),在PtTransferDataComplete中给出了网络帧的后续部分。 方法2中,PtReceivePacket给出了整个网络帧。 你只处理了PtReceive,但如果网卡使用方法2,...... 并且,我在PtReceive没有使用过NdisGetReceivedPacket, 也没有如此使用过MacReceiveContext,MacReceiveContext好像是供NdisTransferData用的。 请阅读 win2000 DDK 的 src\network\ndis\packet\driver 的源代码。 |
|
9楼#
发布于:2001-08-16 19:03
没有想到你使用了passthru的代码。
根据我的体会: passthru的PtReceive中NdisGetReceivedPacket返回的Packet好象基本上为NULL。 其实,其重要部分在switch(pAdapt->Medium)之后,passthru在此通知上层协议下层网卡接收了一个数据帧。 你可以在switch(pAdapt->Medium)前面加入自己的代码,进行帧头处理,并决定是否上转。 passthru仅仅执行了一个传达功能。 |
|
10楼#
发布于:2001-08-16 21:15
我实在是受不了...
看情况你是要过滤icmp包,类似于firewall之类。 此外看情况你是用的passthru。因此平台是w2k, 因为NdisGetReceivedPacket这个函数并不存在于 nt ddk中的ndis4中。我仔细看了看你的代码,发现 我说的全都是废话,因为你的代码很显然就是 passthru。 我不知道你的具体现象,过滤不了icmp,有如下可能 1、包根本就没有走ptrecevie,走的是ptrecievpacket。 2、NdisGetReceivedPacket返回了null 这两种可能都将使你的代码根本没有得到执行。不知道 你用osftice跟踪的结果。 我在这里详细说一下ptreceive的处理情况,然后简单介绍 ptreceivepacket中的处理情况。 对于ptreceive来说,你根本就不需要写这么多代码, 因为ptrecieve的参数headerbuffer只有两种情况, 一种是headbuffersize=14,还有一种就是=packetsize。 先说=14的情况,对于拨号和eth来说,两个地址+一个 类型码,就是14。对于fddi什么的,我记不清是多少。 因此,如果你不过是要过滤icmp的话,根本都不需要 transferdata,此外,你的代码写的颇为垃圾,为什么 要一个字节一个字节比较?为什么不直接强制类型转换 到icmp头的数据结构,这岂不是一下就得到了icmp头了吗? 你的代码里面似乎并不是过滤掉全部icmp,似乎还需要 判断icmp类型,这样的话,你需要得到所有的数据才行。 你需要调用transferdata来得到这些数据,我不喜欢贴 代码,下面简单的说一下transferdata的策略 1、继续按照原有代码的结构,完全仿真真正的miniport行为, 继续用transferdata结构,在imd的协议层的transferdatacomplete 里面得到所有数据包后进行处理,然后调用dismtransferdatacomlete, 2、屏蔽真正的miniport动作,在下面不调用这个函数,直接用imd的 协议身份调用ndistransferdata, 让ndis去调用miniport的 transferdata,miniport driver发送结束后就会调用imd的协议层的 transferdatacomplete,这样imd的协议层就得到所有数据,然后修 改包内容,然后用imd的miniport身份调用 ndismindicatereceivepacket,通知ip层说来了一个数据包。这样的 话,ip层永远不会调用imd里面的miniport的transferdata函数, 这样做的效率节省了ip调用imd miniport的transferdata过程,效率 相对要高一些。 你的情况用第2种策略比较合适,虽然passthru显然是用第一种。 用第2种策略的话,根本就不需要调用那一堆介质相关的 NdisMEthIndicateReceive,NdisMTrIndicateReceive之类。 如果NdisGetReceivedPacket不返回null的话,那么你直接 得到了ndispacket结构,你要做的事情就是从这个结构中 得到所有的数据。调用如下函数: UINT CopyPacket2Buf( IN PNDIS_PACKET Packet, OUT PUCHAR pPacketContent, OUT UINT* pPacketSize) { UINT bufLength; MDL* pNext; UINT i; PUCHAR pbuf; NdisQueryPacket(Packet,NULL,NULL,NULL,pPacketSize); NdisQueryBufferSafe(Packet->Private.Head,&pbuf,&bufLength, 32 ); NdisMoveMemory(pPacketContent,pbuf,bufLength); i=bufLength; pNext=Packet->Private.Head; // next 是一个mdl for(;;) { if(pNext==Packet->Private.Tail) break; pNext=pNext->Next; // next 是一个mdl if (pNext==NULL) break; NdisQueryBufferSafe(pNext,&pbuf,&bufLength,32); NdisMoveMemory(pPacketContent+i,pbuf,bufLength); i+=bufLength; } ASSERT(*pPacketSize == i); return *pPacketSize; } 这个函数是我很早以前写的,当时萝卜快了不洗泥,犯规的用了很多 的内部参数,ms说应该用它提供的宏,但是我当时实在没有时间去慢 慢找那些宏。 得到了buf之后,解析数据包,《程序设计指南》里面专门 提到了如何用可变参数函数简洁的解析各种数据包,建议好好看看。 对于ptreceivepacket,情况一样,因为一下子就从入口参数 得到了ndis提交的一个ndispacket。 |
|
|