这一篇仅对smtp协议解析的思路做整体描述,所有内容均是按照自己理解所写,肯定有理解不正确的地方,请指出,谢谢。
一。Suricata解析smtp协议整体思路
Smtp协议解析模块根据客户端与邮件服务器之间的每一个smtp交互命令,设置了多个状态即当前的smtp命令和解析阶段。Smtp协议解析模块将smtp的交互过程视为一次事务,该事务记录了状态变化和解析阶段的过程,每次状态变化时,根据数据传输方向(客户到服务器,服务器到客户),根据当前方向对当前状态进行相应的处理。
例如:当客户端发送HELO命令后,事务的状态变为HELO,此时,服务器的操作就是处理HELO后反馈数据给客户端,客户端的操作就是解析服务器对HELO命令反馈的数据。
解析方式:smtp解析模块是以行为单位解析,传入处理函数的缓冲区是\r\n前的数据,不包含\r\n,长度也不包含\r\n.
Smtp解析模块对收到的数据查找\r\n,如果未找到则对数据缓存,知道找到\r\n再进行解析处理,如果数据中包括多行即多个\r\n,则每次处理一行后再根据\r\n的位置进行数据偏移处理下一行数据。
源文件:
src/app-layer-smtp.c
src/util-decode-mime.c
二。Suricata解析smtp头部数据,信件头部字段比较简单
到服务器方向的数据处理:SMTPParse->SMTPGetLine:SMTPProcessRequest
SMTPGetLine:
这个函数功能主要是在收到的数据中,查找行分隔符即\r\n,然后将mime_state->current_line指针指向这一行,并设置长度mime_state->current_line_len的长度,注意,这里的currnet_line和current_line_len不包含\r\n两个字符,如果没有找到\r\n则缓存这行数据,下一次继续同样的处理。
SMTPProcessRequest:
- SMTPGetLine设置好current_line和长度后,在该解析处理每行数据,主要是比较数据头部几个字节,根据smtp命令长度判断smtp命令。
- 如果找到smtp命令,则解析命令并提取命令后的参数(如果有)。
- 将命令和参数保持到smtp事务结构体中,并设置当前解析命令、解析状态,例如遇到data命令,则设置mime_state->current_command=SMTP_COMMAND_DATA,设置mime_state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE。
- smtp命令保存到了事务结构体的一个命令数组中,客户端收到服务器的响应时,根据这个命令数组解析其的对应的响应数据的格式。
到客户端方向的数据处理:SMTPParse->SMTPGetLine:SMTPProcessReply
SMTPGetLine的功能同上。
SMTPProcess