关于解决应用层提取NDIS驱动数据包丢包的方案,通过event加共享内存实现

来源:互联网 发布:乌鲁木齐seo软件 编辑:程序博客网 时间:2024/06/05 06:58
关于解决应用层提取NDIS驱动数据包丢包的方案,通过event加共享内存实现
截获的网络封包,很多时候都需要将包的信息或者是包的内容通过win32层显示出来,很多人想到的方法是event加IOCTL,不过这样很容易产生丢包的问题,因为网络接受发送数据包的速度原比event 和 IOCTL的速度要快,也就是说当一个event发到win32层时,win32层通过DeviceIoControl得到数据的时候,原来自己预先定义的缓冲区已经被覆盖了多少遍了。在网上听过高手们通过信号加队列来实现,来一个包信号自加1,win32层来读队列,读一个包信号自减1,不过我翻MSDN好几遍,也没有找到信号量到底是什么东西,只有自己琢磨。
我实现的方法和信号量加队列有点相类似,是通过event和共享内存实现。我实现的比较简单,没有将包的内容提取,只是将包的类型地址信息传到win32层进行显示。
想必如何进行driver和win32通讯和通过共享内存进行传输数据已经很熟悉了吧,(如果不懂可以去www.driverdevelop.com论坛去看看吧,上面还有例子,我就不在这里充了)。我申请了1K字节的内存空间,然后定义包的信息结构
typedef struct _WY_RECORD //日志
{
unsigned char WY_SourceIP[4];
unsigned char WY_DestinationIP[4];
unsigned short WY_SourcePort;
unsigned short WY_DestinationPort;
unsigned char WY_Protocol;
unsigned char WY_Action; //对数据包的执行动作
union{
unsigned short WY_TCPCode; //TCP数据包类型
struct{ //ICMP数据包类型和代码
unsigned char WY_Type;
unsigned char WY_Code;
};
};
unsigned long WY_distance; //下一个数据包的偏移量
}WY_RECORD,*WY_PRECORD;
#define RECORD_LENGTH 20
我在内存区域开始的四个字节区域划定了一个结构--日志头。通过它来标示剩下1020个字节中包的分布情况
typedef struct _WY_RECORD_HEADER
{
unsigned char WY_FirstRec; //第一个日志的位置
unsigned char WY_LastRec; //最后一个日志的位置
unsigned short WY_RecNum; //日志数量
}WY_RECORDHEAD,*WY_PRECORDHEAD;
这个内存区域能放51个日志,不过这已经很足够了,因为通常一个通知event到达win32层,win32层准备开始接受数据的时候有三个数据包在内存区域中。WY_LastRec由driver来修改,每增加一个包则自加1,当到达最大时判断WY_RecNum是否为最大,否则从第零块区域填入数据,是则说明win32层没有接受日志则往后都不填充。win32层修改WY_FirstRec,每读取一个数据包则自加1,当WY_RecNum == 0时,停止读。
event如何发送,如果当前上个WY_RecNum == 0 时则发送event,因此需要有一个变量来记录上一次WY_RecNum的值,用全局变量WY_LastNum来保存上一个数值
以下是Driver中添加日志的函数,编码风格是我自创的(WY命名规则)
int WYFilter_AddRecord(IN WY_PRECORD WY_pRecord, IN int WY_isSend)
{
KSPIN_LOCK WY_Spinlock;
KIRQL WY_OldIrql;
if(WY_pRecHeader->WY_RecNum < 51){
if(WY_pRecHeader->WY_FirstRec==0 && WY_pRecHeader->WY_LastRec==0){ file://如果缓冲区尚未记录
WY_pRecord->WY_distance = (WY_pRecHeader->WY_LastRec+1)*RECORD_LENGTH; file://计算下一个日志块的偏移量
memcpy(WY_pRecAddr,(PVOID)WY_pRecord,RECORD_LENGTH);
WY_pRecHeader->WY_LastRec++;
WY_pRecHeader->WY_RecNum++;
KeSetEvent(WY_gbEvt,0,FALSE);
WY_LastRecNum++;
}
else{ //已经记录过

if(WY_pRecHeader->WY_LastRec == 50){
WY_pRecord->WY_distance = 0; //计算下一个日志块的偏移量
memcpy(((WY_PRECORD)WY_pRecAddr+WY_pRecHeader->WY_LastRec),(PVOID)WY_pRecord,RECORD_LENGTH);
WY_pRecHeader->WY_LastRec = 0; //计算最后一个日志块所在的块数
WY_LastRecNum = WY_pRecHeader->WY_RecNum;
}
else{

WY_pRecord->WY_distance = (WY_pRecHeader->WY_LastRec+1)*RECORD_LENGTH;//计算下一个日志块的偏移量
//第一个参数是计算当前需要写入的日志块的实际地址
memcpy(((WY_PRECORD)WY_pRecAddr+WY_pRecHeader->WY_LastRec),(PVOID)WY_pRecord,RECORD_LENGTH);
WY_pRecHeader->WY_LastRec++; //计算最后一个日志块所在的块数
WY_LastRecNum = WY_pRecHeader->WY_RecNum;
}
KeAcquireSpinLock(&WY_Spinlock,&WY_OldIrql);
WY_pRecHeader->WY_RecNum++; //计算日志块数
KeReleaseSpinLock(&WY_Spinlock,WY_OldIrql);
if(WY_LastRecNum == 0 && WY_pRecHeader->WY_RecNum != 0){
KeSetEvent(WY_gbEvt,0,FALSE);
}

}
// return WYFilter_CheckPolicy(&WY_pRecord->WY_PacketContent,WY_isSend); //这里的结构与我的有些出入,
//将最后一个DWORD数据去掉,就是这个结构
}
// return WYFilter_CheckPolicy(&WY_pRecord->WY_PacketContent,WY_isSend);
}
以下时win32层进行读取
DWORD WINAPI GetRecord(LPVOID WY_lpParam)
{
WY_PRECORDHEAD WY_pRecHeader;
WY_PRECORD WY_pRecord;
WY_PRECORD WY_pRecAddr;
CTestDlg *WY_pThis = (CTestDlg*)WY_lpParam;
CCriticalSection WY_cs;
// DWORD WY_dwReturn;

WY_pRecHeader = (WY_PRECORDHEAD)WY_pThis->WY_RecordAddr; //初始化内存地址
WY_pRecord = (WY_PRECORD)(((unsigned long)WY_pThis->WY_RecordAddr)+4);
WY_pRecAddr = (WY_PRECORD)(((unsigned long)WY_pThis->WY_RecordAddr)+4);
// WY_pThis->WY_result.Format("%x",WY_pRecord);
// WY_pThis->WY_List1.AddString(WY_pThis->WY_result);
// WY_pThis->WY_result.Format("%x",WY_pRecAddr);
// WY_pThis->WY_List1.AddString(WY_pThis->WY_result);
while(TRUE){
::WaitForSingleObject(WY_pThis->WY_hEvt,INFINITE);
while(WY_pRecHeader->WY_RecNum > 0){
if(WY_pRecHeader->WY_FirstRec < 50){

// WY_pThis->WY_result.Format("Record Number = %d,First Record : %d,Last Record : %d",WY_pRecHeader->WY_RecNum,WY_pRecHeader->WY_FirstRec,WY_pRecHeader->WY_LastRec);
// WY_pThis->WY_List1.AddString(WY_pThis->WY_result);
WY_pThis->WY_result.Format("%d.%d.%d.%d:%d-->%d.%d.%d.%d:%d %x",
WY_pRecord->WY_PacketContent.WY_SourceIP[0],
WY_pRecord->WY_PacketContent.WY_SourceIP[1],
WY_pRecord->WY_PacketContent.WY_SourceIP[2],
WY_pRecord->WY_PacketContent.WY_SourceIP[3],
WY_pRecord->WY_PacketContent.WY_SourcePort,
WY_pRecord->WY_PacketContent.WY_DestinationIP[0],
WY_pRecord->WY_PacketContent.WY_DestinationIP[1],
WY_pRecord->WY_PacketContent.WY_DestinationIP[2],
WY_pRecord->WY_PacketContent.WY_DestinationIP[3],
WY_pRecord->WY_PacketContent.WY_DestinationPort,
WY_pRecord->WY_PacketContent.WY_Protocol
);
WY_pThis->WY_List1.AddString(WY_pThis->WY_result);
WY_pRecord = (WY_PRECORD)(((unsigned long)WY_pRecAddr)+WY_pRecord->WY_distance);
WY_pRecHeader->WY_FirstRec++;
}
else{

// WY_pThis->WY_result.Format("Record Number = %d,First Record : %d,Last Record : %d",WY_pRecHeader->WY_RecNum,WY_pRecHeader->WY_FirstRec,WY_pRecHeader->WY_LastRec);
// WY_pThis->WY_List1.AddString(WY_pThis->WY_result);
WY_pThis->WY_result.Format("%d.%d.%d.%d:%d-->%d.%d.%d.%d:%d %x",
WY_pRecord->WY_PacketContent.WY_SourceIP[0],
WY_pRecord->WY_PacketContent.WY_SourceIP[1],
WY_pRecord->WY_PacketContent.WY_SourceIP[2],
WY_pRecord->WY_PacketContent.WY_SourceIP[3],
WY_pRecord->WY_PacketContent.WY_SourcePort,
WY_pRecord->WY_PacketContent.WY_DestinationIP[0],
WY_pRecord->WY_PacketContent.WY_DestinationIP[1],
WY_pRecord->WY_PacketContent.WY_DestinationIP[2],
WY_pRecord->WY_PacketContent.WY_DestinationIP[3],
WY_pRecord->WY_PacketContent.WY_DestinationPort,
WY_pRecord->WY_PacketContent.WY_Protocol
);
WY_pThis->WY_List1.AddString(WY_pThis->WY_result);
WY_pRecord = (WY_PRECORD)(((unsigned long)WY_pRecAddr)+WY_pRecord->WY_distance);
WY_pRecHeader->WY_FirstRec = 0;

}
WY_cs.Lock();
WY_pRecHeader->WY_RecNum--;
WY_cs.Unlock();
}

}

}
原创粉丝点击