一、目标:
现有两个大学抓取的packet数据,分片成若干部分,需要从中抽取出流信息( 源mac地址、目的mac地址、源ip地址、目的IP地址、源端口、目的端口、vlan、协议类型、流首包时间、流末包时间、流总大小),并按文件中的packet顺序,将结果输出出来。
二、实现过程:
1、没有沟通好需求是个硬伤,直接导致前面几次提交结果不合格。
2、pcap是二进制文件,花了点时间研究pcap的文件结构和二进制文件的读写方式。
3、数据量非常大,第一组数据packet数约一千万,第二组有一亿以上,对内存分配是个考验。
4、一开始采用了顺序查找,速度非常慢,运行到后期,10秒只能遍历100组数据。在老师提示下采用了hash表来存储,速度果然不同凡响。
5、hash表关键字的选择:
(1)初期:观察了packet数据,发现源ip地址(SrcIP)不一样的情况比较多,因此哈希函数和关键字都直接用它了。冲突解决采用线性散列(加1)。
( 2)中期:初期的冲突还是太多了,到后面速度异常慢,因此哈希函数和关键字都改成了源mac地址、目的mac地址、源ip地址、目的IP地址、源端口、目的端口、vlan、协议类型的和(当然还要对hash表长取模),这么一来冲突小了不少。然而运行至文件末时速度仍然不够。
(3)后期:导师提示了md5算法,即Message Digest Algorithm MD5(消息摘要算法第五版),它的特点是:
①、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
②、容易计算:从原数据计算出MD5值很容易。
③、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
④、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
⑤、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
这就意味着用md5算法作为hash函数可以大大减少冲突(实际情况是基本不出现冲突),毕竟不同关键字算出来的值差异太大了(但并没有直接验证,只是通过运行时间间接得出的结论)。
6、运行时间:一百万个flow大概200s,这比顺序查找简直快了四五个量级。
三、代码
(运行环境为Visual Studio 2012)
主代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "md5.h"
#include<math.h>
#include<time.h>
#define N 13000000LL
#define NUM_OF_MAX_FLOW 13000000LL
static long long index[NUM_OF_MAX_FLOW]={
0},FlowCnt=1;
typedef unsigned char uint8;
typedef struct{
int TimeStart;
int MicroSec;
int Caplen;
uint8 SrcMac[6];
uint8 DstMac[6];
uint8 SrcIP[4];
uint8 DstIP[4];
uint8 SrcPort[2];
uint8 DstPort[2];
uint8 VlanID[2];
uint8 VlanType[2];
uint8 Protocol;
int FlowBytes;
}STREAM;
typedef struct{
uint8 flag;
double timeStart;
double timeEnd;
uint8 SrcMac[6];
uint8 DstMac[6];
uint8 SrcIP[4];
uint8 DstIP[4];
uint8 SrcPort[2];
uint8 DstPort[2];
uint8 VlanID[2];
uint8 VlanType[2];
uint8 Protocol;
unsigned long FlowBytes;
unsigned long PacketsNum;
}FLOW;
static FLOW FlowTable[NUM_OF_MAX_FLOW] = { 0 };
void writeHex(FILE *fw, uint8 *str, int n)
{
int i;
for (i = 0; i<n; i++){
fprintf(fw, "%x%x", (str[i] - str[i] % 16) >> 4, str[i] % 16);
}
return;
}
int isEqual(uint8 *old,uint8 *now,int n)
{
int i;
for(i=0;i<n;i++)
if(old[i]!=now[i]) return 0;
return 1;
}
int Equal(STREAM data,FLOW FlowData)
{
if(isEqual(data.SrcMac,FlowData.SrcMac,6))
if(isEqual(data.DstMac,FlowData.DstMac,6))
if(isEqual(data.SrcIP,FlowData.SrcIP,4))
if(isEqual(data.DstIP,FlowData.DstIP,4))
if(isEqual(data.SrcPort,FlowData.SrcPort,2))
if(isEqual(data.DstPort,FlowData.DstPort,2))
if(isEqual(data.VlanID,FlowData.VlanID,2))
if(isEqual(data.VlanType,FlowData.VlanType,2))
if(data.Protocol==FlowData.Protocol)
return 1;
return 0;
}
long long string2num(uint8 *IP)
{
long long temp = (long long)IP[3];
temp += (long long)IP[2] << 8;
temp += (long long)IP[1] << 16;
temp += (long long)IP[0] << 24;
return temp;
}
int add2Hash(STREAM data,FLOW *FlowTable,long long HashNum)
{
int i,flag=0,cnt=0;
double temp;
loop:
if(cnt++>100000) return 0;
if(FlowTable[HashNum].flag==0){
FlowTable[HashNum].flag=1;
FlowTable[HashNum].timeStart=data.TimeStart+(int)data.MicroSec/1000+(data.MicroSec%1000)/1000.0;
FlowTable[HashNum].timeEnd=FlowTable[HashNum].timeStart;
for(i=0;i<6;i++) FlowTable[HashNum].SrcMac[i]=data.SrcMac[i];
for(i=0;i<6;i++) FlowTable[HashNum].DstMac[i]=data.DstMac[i];
for(i=0;i<4;i++) FlowTable[HashNum].SrcIP[i]=data.SrcIP[i];
for(i=0;i<4;i++) FlowTable[HashNum].DstIP[i]=data.DstIP[i];
for(i=0;i<2;i++) FlowTable[HashNum].SrcPort[i]=data.SrcPort[i];
for(i=0;i<2;i++) FlowTable[HashNum].DstPort[i]=data.DstPort[i];
for(i=0;i<2;i++) FlowTable[HashNum].VlanID[i]=data.VlanID[i];
for(i=0;i<2;i++) FlowTable[HashNum].VlanType[i]=data.VlanType[i];
FlowTable[HashNum].Protocol=data.Protocol;
FlowTable[HashNum].FlowBytes=data.FlowBytes;
FlowTable[HashNum].PacketsNum=1;
index[FlowCnt++]=HashNum;
return 1;
}
else{
//????
if(Equal(data,FlowTable[HashNum]))
{
//???????flow
temp=data.TimeStart+(int)data.MicroSec/1000+(data.MicroSec%1000)/1000.0;
if (fabs(temp - FlowTable[HashNum].timeEnd)<5 && temp>FlowTable[HashNum].timeEnd){
//?????????flow
FlowTable[HashNum].timeEnd=temp;
FlowTable[HashNum].FlowBytes += data.FlowBytes;
FlowTable[HashNum].PacketsNum++;
return 1;
}
else{
/*HashNum=(HashNum*HashNum)%NUM_OF_MAX_FLOW;
add2Hash(data,FlowTable,HashNum);//????????flow?*/
HashNum = (HashNum + 1) % NUM_OF_MAX_FLOW;
while (FlowTable[HashNum].flag == 1){
if (Equal(data, FlowTable[HashNum])){
temp = data.TimeStart + (int)data.MicroSec / 1000 + (data.MicroSec % 1000) / 1000.0;
if (fabs(temp -