小弟现在做一个sniffer,要求能把数据全部还原,但是处理mail时(封装在一个SMTP类里面处理),有个很棘手的问题,所有的数据和包头都是连成一片的,也就是说boundary(就是NEXTPART那个标示)有可能在两个数据包之间,所以目前我只有把两个包组合起来用(程序对效率还有一定的要求,老大不准把所有数据截获完再来处理),但是这样也只减少了1/2概率,而且这样做程序目前都还有问题,关键是解码一个字符都不能多或者少(比如base64解码最明显),而分的段又太多了,难免保证不出意外,有时一个包可能有3个boundary。
那位高手有好点的建议没,小弟谢谢了先。
我也想过干脆把User和Password还原出来,我也去POP3算了,但是又不知道前面User和Password是用的什么算法,请高手指点。
不知道邮件服务器一般是怎么解决解码的问题的?
那位高手有好点的建议没,小弟谢谢了先。
我也想过干脆把User和Password还原出来,我也去POP3算了,但是又不知道前面User和Password是用的什么算法,请高手指点。
不知道邮件服务器一般是怎么解决解码的问题的?
参考rfc。
bool SMTP::DealWithSmtp(char *pdata,int len ,unsigned long ackno)
{
char *datapos=NULL;
char *nextdata=NULL;
CString infotemp,strtemp;
static int bufnum=0;
//char *findbound="find the bound!";
maildata.Write(pdata, len);
if(m_first)
{
m_firstsourceip=GetSourceip();
m_first =false;
m_helloOver=true;
}
if(*pdata=='Q'&& *(pdata+1)=='U'&& *(pdata+2)=='I' && *(pdata+3)=='T')
{
m_first =true;
m_mailbegin=false;
m_infoOver=false;
// m_creflag =false;
m_firstackno=0;
return true;
}
if(m_helloOver)
if(m_firstsourceip==GetSourceip())
datapos =GetMailInfo(pdata,len); if(m_firstsourceip==GetSourceip())
if(m_firstackno==ackno)
if(m_infoOver)
{
bufnum++;
if(bufnum%2)
{ strncpy(m_twobuf,pdata,len);//用twobuf来控制
prelen=len;
}
else
{
strncpy(m_twobuf+prelen,pdata,len);
len+=prelen;
if(nextdata=Findboundary(m_twobuf,len)) //找寻是否存在BOUND,如果有返回找到后的位置,这里开始和下面其实是一样的了
{
WriteToFile(m_twobuf,m_findbound);
datapos=GetboundInfo(nextdata,m_leavelen); //如果存在一个BOUND则取它的信息和
//并返回位置datapos
if(m_findbound<0) //处理特殊情况
m_findbound=0;
FindNewFile();
GetBodyLen(datapos,m_leavelen); //根据取的BOUND后的位置取主体的长度
WriteToFile(datapos,m_bodylen);
m_leavelen-=m_bodylen; //得到剩余长度,bodylen置空,以便下次使用
m_bodylen=0;
while(m_leavelen) //如果还有剩余
{
if(nextdata=Findboundary(datapos,m_leavelen))//如果剩余文件中还有BOUND,重复取得
{
datapos=GetboundInfo(nextdata,m_leavelen);
GetBodyLen(datapos,m_leavelen);
FindNewFile();
WriteToFile(datapos,m_bodylen);
m_leavelen-=m_bodylen;
datapos+=(m_bodylen+4);
m_bodylen=0;
}
else //没有BOUND了,直接写入
{
WriteToFile(datapos,m_leavelen);
m_leavelen=0;
break;
} }
}
else
{
WriteToFile(m_twobuf,len);
}
for(int i=0;i<3000;i++)
m_twobuf[i]=0;
}
}
if(m_CanGetInfo)
{
for(int j=0;j<9;j++)
{
if(m_fielddata[j])
{
strtemp.Format("%s",m_fielddata[j]);
infotemp+=strtemp;
infotemp+="\r\n";
}
} mailusedata.Write(infotemp, infotemp.GetLength());
m_helloOver=false;
m_firstackno=ackno;
m_infoOver=true;
m_CanGetInfo=false;
m_textbound=Gettextbound();
if((m_infolen+4) < len)
{
if(nextdata=Findboundary(datapos,len-m_infolen))
{
datapos=GetboundInfo(nextdata,m_leavelen);
m_filebound=Getfilebound();
while(m_leavelen)
{
if(nextdata=Findboundary(datapos,m_leavelen)) //nextdata为bound参数的位置,如果跳出则m_leavelen减
{
datapos=GetboundInfo(nextdata,m_leavelen); //datapos是主体数据的位置,如果跳出则m_leavelen减
FindNewFile();
GetBodyLen(datapos,m_leavelen);
WriteToFile(datapos,m_bodylen);
m_leavelen-=m_bodylen;
datapos+=(m_bodylen+4);
m_bodylen=0;
}
else
{
WriteToFile( datapos , m_leavelen);
m_leavelen=0;
break;
}
}
}
else
{
WriteToFile( datapos , len-m_infolen);
}
}
// maildata.Write(pdata, len);
}
return true;
}
所有的SMTP处理也就在这个DealWith里面,上面一部分和下面差不多,只是条件不一样。
这个程序目前还有丢失字符的问题,高手请指出来。
如果是一个zip文件呢,拿了半个你去处理看看.
截取就负责截取,截获的数据放在内存或磁盘缓冲区里,开其他线程处理,或者
干脆在停止sniffer后做数据分析,象iris之类的都是这么做的.
还有,用多线程边接收边处理,只要得到了头信息也应该是可行的啊,比如我得到了文件名信息,后来的同一个ACKNO就把他写入一个文件就行了。
实时的话,就应该做成状态机。smtp协议控制块也是有不同状态的。
我看这样做的开销,比你复制到一个大buf里再处理要大.
22
------=_NextPart_000_0063_01C
23 10.150.1.10----->202.108.44.204 大小为:1452
SeqNo: 670762205----->AckNo: -189272848
2FE7D.E4DFE240 //这个就是boundary的直
这样的情况怎么办?
一开始说"程序对效率还有一定的要求,老大不准把所有数据截获完再来处理",
然后又倒过来了"截获的数据全部都已经在一个LIST中,问题是要不要再把LIST的中的SMTP数据复制一个到BUF(有可能很大)来专门接收SMTP信息然后处理"
你把数据全放在buf list里就是为了不在截获的同时做parse,就是为了不实时的做parse,现在又说"说白了就是要基本上实时的来处理"
我就搞不懂了,你到底要什么??
while(more_pkts_in_list)
{
get a packet;
while(packet.有回车)
{
把回车前的内容拼凑到unhandled中,得到一整行
handleline();//处理之
}
把最后一个回车后的保存到unhandled中
}对handleline来说,就是一行一行处理了。
buflist接收到一个buf才AddTail()加入到list中,不说了,现在方法已经定了--边接收边处理,我们最后要做的是个防火墙,不可能接收完了才处理,这样机器早就挂了。
sniffer用作截获分析网络数据,分析某些数据可能需要比较多的时间,可以非实时,
防火墙当然必须是实时的,拿防火墙做sniffer的事情,这种设计在效率上可行吗??
防火墙?要做邮件过滤吗?这个sniffer可不行
我说了"/r/n"了吗?你看看清楚,我说的是"邮件正文以\r\n.\r\n结束",这是一个例子.
QUIT是什么?smtp会话结束才是QUIT,这时候可能已经发了100封信了.
还有,你懂不懂什么是list?说了半天,你认为buf list是物理空间连续的buffer?
=C0=F1=A3=A1
=09=09=09=09=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1robin
153 顺序号:260929923 确认号:8603353 10.150.1.10----->202.108.44.205 大小为:6 QUIT
还有我什么时候说了buflist是物理上连续的,难道我不知道把他们一个个取出来再写到一个BigBuf里面?
没你想的这么笨。
我是菜鸟,我不和ahao(天·狼·星星)这样只能够咬文嚼字挑毛病的大虾比。